Repository: vega/vega-lite
Pull request #641 (2015-10-13 05:31:58)

Run schema validation over a bunch of examples
Test against the vl and vg schema. 


Patch:
diff --git a/editor/validate.js b/editor/validate.js
index 33fe5b157..911e87e03 100644
--- a/editor/validate.js
+++ b/editor/validate.js
@@ -1,6 +1,6 @@
 'use strict';
 
-/*global vl, d3, ZSchema */
+/*global vl, d3, ZSchema, validateVl, validateVg */
 
 var vgSchema = null;
 
diff --git a/gallery.html b/gallery.html
index 6b80253b4..b7b528a04 100644
--- a/gallery.html
+++ b/gallery.html
@@ -34,6 +34,7 @@
   </div>
 
   <a href="https://github.com/uwdata/vega-lite"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>
+  <script src="gallery/examples.js"></script>
   <script src="gallery/gallery.js"></script>
   <script>
     (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
@@ -45,4 +46,4 @@
     ga('send', 'pageview');
   </script>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/gallery/examples.js b/gallery/examples.js
new file mode 100644
index 000000000..56114905a
--- /dev/null
+++ b/gallery/examples.js
@@ -0,0 +1,216 @@
+'use strict';
+
+var EXAMPLES = [
+  {
+    title: 'Simple Bar Chart',
+    description: 'A simple bar chart with embedded data.',
+    spec: {
+      data: {
+        values: [
+          {'x':'A', 'y':28}, {'x':'B', 'y':55}, {'x':'C', 'y':43},
+          {'x':'G', 'y':19}, {'x':'H', 'y':87}, {'x':'I', 'y':52},
+          {'x':'D', 'y':91}, {'x':'E', 'y':81}, {'x':'F', 'y':53}
+        ]
+      },
+      marktype: 'bar',
+      encoding: {
+        y: {type: 'Q', name: 'y'},
+        x: {type: 'O', name: 'x'}
+      }
+    }
+  },{
+    title: 'Aggregate Bar Chart',
+    spec: {
+      'marktype': 'bar',
+      'encoding': {
+        'x': {'name': 'Cylinders','type': 'O'},
+        'y': {'name': 'Acceleration','type': 'Q','aggregate': 'mean'}
+      },
+      'data': {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Grouped bar chart',
+    spec: {
+      marktype: 'bar',
+      encoding: {
+        x: {name: 'Origin', type: 'N'},
+        y: {name: 'Acceleration',type: 'Q', aggregate: 'mean'},
+        col: { axis: {maxLabelLength: 25}, name: 'Cylinders',type: 'O'},
+        color: {
+          scale: {quantitativeRange: ['#AFC6A3','#09622A']},
+          name: 'Origin',
+          type: 'N'
+        }
+      },
+      data: {url: 'data/cars.json'}
+    }
+  },{
+    title: 'Scatter plot.',
+    description: 'Horse power and miles per gallon',
+    spec: {
+      marktype: 'point',
+      encoding: {
+        x: {'name': 'Horsepower','type': 'Q'},
+        y: {'name': 'Miles_per_Gallon','type': 'Q'}
+      },
+      data: {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Binned Scatter plots',
+    spec: {
+      'marktype': 'point',
+      'encoding': {
+        'x': {'bin': true,'name': 'Displacement','type': 'Q'},
+        'y': {'bin': true,'name': 'Miles_per_Gallon','type': 'Q'},
+        'size': {
+          'name': '*',
+          'aggregate': 'count',
+          'type': 'Q',
+          'displayName': 'Number of Records'
+        }
+      },
+      'data': {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Scatter Plot with Ordinal on Top',
+    spec: {
+      'marktype': 'point',
+      'encoding': {
+        'x': {'name': 'MPAA_Rating','type': 'N'},
+        'y': {'name': 'Release_Date','type': 'N'}
+      },
+      'data': {'url': 'data/movies.json'}
+    }
+  },{
+    title: 'Line Chart',
+    description: 'Horse power over time',
+    spec: {
+      marktype: 'line',
+      encoding: {
+        x: {'name': 'Year','type': 'T','timeUnit': 'year'},
+        y: {'name': 'Horsepower','type': 'Q','aggregate': 'mean'}
+      },
+      data: {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Histogram',
+    spec: {
+      marktype: 'bar',
+      encoding: {
+        x: {'bin': {'maxbins': 15},'name': 'Horsepower','type': 'Q'},
+        y: {'name': '*','type': 'Q','aggregate': 'count'}
+      },
+      data: {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Stacked Histogram',
+    description: 'Simple histogram with bars broken down by the number of cylinders. Also has a legend.',
+    spec: {
+      marktype: 'bar',
+      encoding: {
+        x: {'bin': {'maxbins': 15},'name': 'Horsepower','type': 'Q'},
+        y: {'name': '*','type': 'Q','aggregate': 'count'},
+        color: {'name': 'Cylinders','type': 'N'}
+      },
+      data: {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Area chart',
+    spec: {
+      'marktype': 'area',
+      'encoding': {
+        'x': {'name': 'Year','type': 'T','timeUnit': 'year'},
+        'y': {'name': 'Weight_in_lbs','type': 'Q','aggregate': 'sum'}
+      },
+      'data': {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Stacked Area chart',
+    spec: {
+      'marktype': 'area',
+      'encoding': {
+        'x': {'name': 'Year','type': 'T','timeUnit': 'year'},
+        'y': {'name': 'Weight_in_lbs','type': 'Q','aggregate': 'sum'},
+        'color': {'name': 'Cylinders', 'type': 'O'}
+      },
+      'data': {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Trellis Area chart',
+    spec: {
+      'marktype': 'area',
+      'encoding': {
+        'x': {'name': 'Year','type': 'T','timeUnit': 'year'},
+        'y': {'name': 'Weight_in_lbs','type': 'Q','aggregate': 'sum'},
+        'col': {'name': 'Cylinders', 'type': 'O'}
+      },
+      'data': {'url': 'data/cars.json'}
+    }
+  },{
+    title: 'Stacked Bar Chart',
+    spec: {
+      'marktype': 'bar',
+      'encoding': {
+        'x': {'name': 'variety','type': 'N'},
+        'y': {'name': 'yield','type': 'Q','aggregate': 'sum'},
+        'color': {'name': 'site', 'type': 'N'}
+      },
+      'data': {'url': 'data/barley.json'}
+    }
+  },{
+    title: 'Trellis Stacked Bar Chart',
+    spec: {
+      'marktype': 'bar',
+      'encoding': {
+        'x': {'name': 'variety','type': 'N'},
+        'y': {'name': 'yield','type': 'Q','aggregate': 'sum'},
+        'col': {'name': 'year','type': 'O'},
+        'color': {'name': 'site', 'type': 'N'}
+      },
+      'data': {'url': 'data/barley.json'}
+    }
+  },{
+    title: 'Trellis Plot',
+    spec: {
+      'marktype': 'point',
+      'encoding': {
+        'x': {'name': 'Worldwide_Gross','type': 'Q'},
+        'y': {'name': 'US_DVD_Sales','type': 'Q'},
+        'col': {'axis': {'maxLabelLength': 25},'name': 'MPAA_Rating','type': 'O'}
+      },
+      'data': {'url': 'data/movies.json'}
+    }
+  },{
+    title: 'Trellis Plot, sorted by mean yield.',
+    // TODO: find source of this example and write better description
+    description: 'Classic Barley Example',
+    spec: {
+      data: {url: 'data/barley.json'},
+      marktype: 'point',
+      encoding: {
+        x: {type: 'Q',name: 'yield', aggregate: 'mean'},
+        y: {
+          sort: {field: 'yield', op: 'mean'},
+          type: 'O',
+          name: 'variety'
+        },
+        row: {type: 'O',name: 'site'},
+        color: {type: 'N',name: 'year'}
+      }
+    }
+  },{
+    title: 'Text Heatmap',
+    spec: {
+      'marktype': 'text',
+      'encoding': {
+        'row': {'name': 'Origin','type': 'O'},
+        'col': {'name': 'Cylinders','type': 'O'},
+        'color': {'name': 'Horsepower','type': 'Q','aggregate': 'mean'},
+        'text': {'name': '*','type': 'Q','aggregate': 'count'}
+      },
+      'data': {'url': 'data/cars.json'}
+    }
+  }
+];
+
+module.exports = EXAMPLES;
diff --git a/gallery/gallery.js b/gallery/gallery.js
index c81908eb1..d199ada74 100644
--- a/gallery/gallery.js
+++ b/gallery/gallery.js
@@ -1,219 +1,6 @@
 'use strict';
 
-/*global vl, d3, vg, angular, alert, validateVl, validateVg */
-
-var EXAMPLES = [
-  {
-    title: 'Simple Bar Chart',
-    description: 'A simple bar chart with embedded data.',
-    spec: {
-      data: {
-        values: [
-          {'x':'A', 'y':28}, {'x':'B', 'y':55}, {'x':'C', 'y':43},
-          {'x':'G', 'y':19}, {'x':'H', 'y':87}, {'x':'I', 'y':52},
-          {'x':'D', 'y':91}, {'x':'E', 'y':81}, {'x':'F', 'y':53}
-        ]
-      },
-      marktype: 'bar',
-      encoding: {
-        y: {type: 'Q', name: 'y'},
-        x: {type: 'O', name: 'x'}
-      }
-    }
-  },{
-    title: 'Aggregate Bar Chart',
-    spec: {
-      'marktype': 'bar',
-      'encoding': {
-        'x': {'name': 'Cylinders','type': 'O'},
-        'y': {'name': 'Acceleration','type': 'Q','aggregate': 'mean'}
-      },
-      'data': {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Grouped bar chart',
-    spec: {
-      marktype: 'bar',
-      encoding: {
-        x: {name: 'Origin', type: 'N'},
-        y: {name: 'Acceleration',type: 'Q', aggregate: 'mean'},
-        col: { axis: {maxLabelLength: 25}, name: 'Cylinders',type: 'O'},
-        color: {
-          scale: {quantitativeRange: ['#AFC6A3','#09622A']},
-          name: 'Origin',
-          type: 'N'
-        }
-      },
-      data: {url: 'data/cars.json'}
-    }
-  },{
-    title: 'Scatter plot.',
-    description: 'Horse power and miles per gallon',
-    spec: {
-      marktype: 'point',
-      encoding: {
-        x: {'name': 'Horsepower','type': 'Q'},
-        y: {'name': 'Miles_per_Gallon','type': 'Q'}
-      },
-      data: {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Binned Scatter plots',
-    spec: {
-      'marktype': 'point',
-      'encoding': {
-        'x': {'bin': true,'name': 'Displacement','type': 'Q'},
-        'y': {'bin': true,'name': 'Miles_per_Gallon','type': 'Q'},
-        'size': {
-          'name': '*',
-          'aggregate': 'count',
-          'type': 'Q',
-          'displayName': 'Number of Records'
-        }
-      },
-      'data': {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Scatter Plot with Ordinal on Top',
-    spec: {
-      'marktype': 'point',
-      'encoding': {
-        'x': {'name': 'MPAA_Rating','type': 'N'},
-        'y': {'name': 'Release_Date','type': 'N'}
-      },
-      'data': {'url': 'data/movies.json'}
-    }
-  },{
-    title: 'Line Chart',
-    description: 'Horse power over time',
-    spec: {
-      marktype: 'line',
-      encoding: {
-        x: {'name': 'Year','type': 'T','timeUnit': 'year'},
-        y: {'name': 'Horsepower','type': 'Q','aggregate': 'mean'}
-      },
-      data: {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Histogram',
-    spec: {
-      marktype: 'bar',
-      encoding: {
-        x: {'bin': {'maxbins': 15},'name': 'Horsepower','type': 'Q'},
-        y: {'name': '*','type': 'Q','aggregate': 'count'}
-      },
-      data: {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Stacked Histogram',
-    description: 'Simple histogram with bars broken down by the number of cylinders. Also has a legend.',
-    spec: {
-      marktype: 'bar',
-      encoding: {
-        x: {'bin': {'maxbins': 15},'name': 'Horsepower','type': 'Q'},
-        y: {'name': '*','type': 'Q','aggregate': 'count'},
-        color: {'name': 'Cylinders','type': 'N'}
-      },
-      data: {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Area chart',
-    spec: {
-      'marktype': 'area',
-      'encoding': {
-        'x': {'name': 'Year','type': 'T','timeUnit': 'year'},
-        'y': {'name': 'Weight_in_lbs','type': 'Q','aggregate': 'sum'}
-      },
-      'data': {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Stacked Area chart',
-    spec: {
-      'marktype': 'area',
-      'encoding': {
-        'x': {'name': 'Year','type': 'T','timeUnit': 'year'},
-        'y': {'name': 'Weight_in_lbs','type': 'Q','aggregate': 'sum'},
-        'color': {'name': 'Cylinders', 'type': 'O'}
-      },
-      'data': {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Trellis Area chart',
-    spec: {
-      'marktype': 'area',
-      'encoding': {
-        'x': {'name': 'Year','type': 'T','timeUnit': 'year'},
-        'y': {'name': 'Weight_in_lbs','type': 'Q','aggregate': 'sum'},
-        'col': {'name': 'Cylinders', 'type': 'O'}
-      },
-      'data': {'url': 'data/cars.json'}
-    }
-  },{
-    title: 'Stacked Bar Chart',
-    spec: {
-      'marktype': 'bar',
-      'encoding': {
-        'x': {'name': 'variety','type': 'N'},
-        'y': {'name': 'yield','type': 'Q','aggregate': 'sum'},
-        'color': {'name': 'site', 'type': 'N'}
-      },
-      'data': {'url': 'data/barley.json'}
-    }
-  },{
-    title: 'Trellis Stacked Bar Chart',
-    spec: {
-      'marktype': 'bar',
-      'encoding': {
-        'x': {'name': 'variety','type': 'N'},
-        'y': {'name': 'yield','type': 'Q','aggregate': 'sum'},
-        'col': {'name': 'year','type': 'O'},
-        'color': {'name': 'site', 'type': 'N'}
-      },
-      'data': {'url': 'data/barley.json'}
-    }
-  },{
-    title: 'Trellis Plot',
-    spec: {
-      'marktype': 'point',
-      'encoding': {
-        'x': {'name': 'Worldwide_Gross','type': 'Q'},
-        'y': {'name': 'US_DVD_Sales','type': 'Q'},
-        'col': {'axis': {'maxLabelLength': 25},'name': 'MPAA_Rating','type': 'O'}
-      },
-      'data': {'url': 'data/movies.json'}
-    }
-  },{
-    title: 'Trellis Plot, sorted by mean yield.',
-    // TODO: find source of this example and write better description
-    description: 'Classic Barley Example',
-    spec: {
-      data: {url: 'data/barley.json'},
-      marktype: 'point',
-      encoding: {
-        x: {type: 'Q',name: 'yield', aggregate: 'mean'},
-        y: {
-          sort: {field: 'yield', op: 'mean'},
-          type: 'O',
-          name: 'variety'
-        },
-        row: {type: 'O',name: 'site'},
-        color: {type: 'N',name: 'year'}
-      }
-    }
-  },{
-    title: 'Text Heatmap',
-    spec: {
-      'marktype': 'text',
-      'encoding': {
-        'row': {'name': 'Origin','type': 'O'},
-        'col': {'name': 'Cylinders','type': 'O'},
-        'color': {'name': 'Horsepower','type': 'Q','aggregate': 'mean'},
-        'text': {'name': '*','type': 'Q','aggregate': 'count'}
-      },
-      'data': {'url': 'data/cars.json'}
-    }
-  }
-];
+/*global vl, d3, vg, angular, alert, validateVl, validateVg, EXAMPLES */
 
 var app = angular.module('app', []);
 


Test patch:
diff --git a/test/examples.js b/test/examples.js
new file mode 100644
index 000000000..cde35de66
--- /dev/null
+++ b/test/examples.js
@@ -0,0 +1,27 @@
+var __ = require('lodash');
+
+var f = require('./fixtures'),
+  galleryExamples = require('../gallery/examples');
+
+var e = [];
+
+var addTitles = function(examples, name) {
+  var  i = 1;
+  return examples.reduce(function(aggregator, example) {
+    aggregator.push({
+      spec: example,
+      title: name + ' ' + i++
+    });
+    return aggregator;
+  }, []);
+};
+
+e = e.concat(addTitles(__.values(f.bars), 'bars'));
+e = e.concat(addTitles(__.values(f.points), 'points'));
+e = e.concat(addTitles(__.values(f.lines), 'lines'));
+e = e.concat(addTitles(__.values(f.area), 'area'));
+
+// TODO(#640): fix validation errors
+// e = e.concat(galleryExamples);
+
+module.exports = e;
diff --git a/test/fixtures.js b/test/fixtures.js
index e81762928..5b4fc6ea5 100644
--- a/test/fixtures.js
+++ b/test/fixtures.js
@@ -121,7 +121,7 @@ f.lines['x,y'] = {
 f.lines['x,y,stroke'] = {
   "marktype": "line",
   "encoding": {
-    "x": {"name": "name","type": "N"},
+    "x": {"name": "Name","type": "N"},
     "y": {"name": "Cylinders","type": "O"},
     "color": {"name": "Acceleration","type": "Q"}
   },
@@ -151,4 +151,5 @@ f.area['x,y,stroke'] = {
   "data": {"url": "data/cars.json"}
 };
 
-module.exports = f;
\ No newline at end of file
+
+module.exports = f;
diff --git a/test/schema.spec.js b/test/schema.spec.js
index 0569202e0..d150a08d6 100644
--- a/test/schema.spec.js
+++ b/test/schema.spec.js
@@ -1,12 +1,12 @@
 'use strict';
 
 var assert = require('assert'),
-  ZSchema = require("z-schema"),
+  ZSchema = require('z-schema'),
   inspect = require('util').inspect;
 
 var schema = require('../lib/schema.json'),
-  util = require('../src/schema/schemautil.js'),
-  specSchema = require('../src/schema/schema.js').schema;
+  util = require('../src/schema/schemautil'),
+  specSchema = require('../src/schema/schema').schema;
 
 /*jshint -W121 */
 String.prototype.endsWith = function(suffix) {
diff --git a/test/validate.spec.js b/test/validate.spec.js
new file mode 100644
index 000000000..4f9c98062
--- /dev/null
+++ b/test/validate.spec.js
@@ -0,0 +1,52 @@
+'use strict';
+
+var expect = require('chai').expect,
+  ZSchema = require('z-schema'),
+  inspect = require('util').inspect,
+  dl = require('datalib');
+
+var vl = require('../src/vl.js'),
+  vlSchema = require('../src/schema/schema').schema,
+  vgSchema = require('../node_modules/vega/vega-schema.json'),
+  examples = require('./examples');
+
+
+describe('Examples', function() {
+
+  examples.forEach(function(example) {
+    validateAgainstSchemas(example.spec, example.title);
+  });
+
+  var validator = new ZSchema();
+  var errors;
+
+  function validateAgainstSchemas(vlspec, title) {
+    it('should be valid and produce valid vega for: ' + title, function() {
+      var isVlValid = validator.validate(vlspec, vlSchema);
+
+      if (!isVlValid) {
+        errors = validator.getLastErrors();
+        console.log(inspect(errors, { depth: 10, colors: true }));
+      }
+      expect(isVlValid).to.eql(true);
+
+      var stats;
+
+      if (vlspec.data.url) {
+        var data = dl.read(dl.load({
+          file: vlspec.data.url
+        }), {type: 'json', parse: 'auto'});
+        stats = vl.data.stats(data);
+      }
+      var vegaSpec = vl.compile(vlspec, stats);
+
+      var isVgValid = validator.validate(vegaSpec, vgSchema);
+
+      if (!isVgValid) {
+        errors = validator.getLastErrors();
+        console.log(inspect(errors, { depth: 10, colors: true }));
+      }
+      expect(isVgValid).to.eql(true);
+    });
+  }
+});