Browse Source

Adding more tests; beginnings of a refactor to make compilers more configurable

dev/git-series/gccdum
Matt Godbolt 6 years ago
parent
commit
bc5848fa58
  1. 1
      Makefile
  2. 3
      etc/config/c++.lud-mgodbolt01.properties
  3. 107
      lib/compilation-env.js
  4. 223
      lib/compile.js
  5. 4
      lib/properties.js
  6. 8
      package.json
  7. 50
      test/compilation-env.js
  8. 94
      test/filter-tests.js

1
Makefile

@ -51,7 +51,6 @@ node_modules: $(NODE_MODULES)
bower_modules: $(BOWER_MODULES)
test: $(NODE_MODULES) lint
(cd test; $(NODE) test.js)
$(MAKE) -C c-preload test
@echo Tests pass

3
etc/config/c++.lud-mgodbolt01.properties

@ -1,6 +1,7 @@
# Default settings for GCC Explorer.
defaultCompiler=g52
compilers=g44:g45:g46:clang35:g51:g52:gdef:msp430g453:cl
#compilers=g44:g45:g46:clang35:g51:g52:gdef:msp430g453:cl
compilers=gdef
#compilers=g44:g45:g46:clang35:g51:g52:gdef:AWS
#compilers=localhost@20480
compiler.g44.exe=/usr/bin/g++-4.4

107
lib/compilation-env.js

@ -0,0 +1,107 @@
// Copyright (c) 2012-2016, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
var LRU = require('lru-cache'),
Promise = require('promise'), // jshint ignore:line
Queue = require('promise-queue'),
child_process = require('child_process'),
logger = require('./logger').logger,
_ = require('underscore-node');
Queue.configure(Promise);
function CompilationEnvironment(gccProps) {
this.okOptions = new RegExp(gccProps('optionsWhitelistRe', '.*'));
this.badOptions = new RegExp(gccProps('optionsBlacklistRe', '(?!)'));
this.cache = LRU({
max: gccProps('cacheMb') * 1024 * 1024,
length: function (n) {
return JSON.stringify(n).length;
}
});
this.cacheHits = 0;
this.cacheMisses = 0;
this.compileQueue = new Queue(gccProps("maxConcurrentCompiles", 1), Infinity);
this.multiarch = null;
try {
var multi = child_process.execSync("gcc -print-multiarch").toString().trim();
if (multi) {
logger.info("Multiarch: " + multi);
this.multiarch = multi;
} else {
logger.info("No multiarch");
}
} catch (err) {
logger.warn("Unable to get multiarch: " + err);
}
}
CompilationEnvironment.prototype.getEnv = function (needsMulti) {
var env = {
PATH: process.env.PATH
};
if (needsMulti && this.multiarch) {
env.LIBRARY_PATH = '/usr/lib/' + this.multiarch;
env.C_INCLUDE_PATH = '/usr/include/' + this.multiarch;
env.CPLUS_INCLUDE_PATH = '/usr/include/' + this.multiarch;
}
return env;
};
CompilationEnvironment.prototype.cacheStats = function () {
var total = this.cacheHits + this.cacheMisses;
if ((total % 100) == 1) {
var pc = (100 * this.cacheHits) / total;
logger.info("Cache stats: " + this.cacheHits + " hits, " + this.cacheMisses + " misses (" + pc.toFixed(2) +
"%), LRU has " + this.cache.itemCount + " item(s) totalling " + this.cache.length + " bytes");
}
};
CompilationEnvironment.prototype.cacheGet = function (key) {
var cached = this.cache.get(key);
if (cached) {
this.cacheStats();
this.cacheHits++;
return cached;
}
this.cacheMisses++;
return undefined;
};
CompilationEnvironment.prototype.cachePut = function (key, result) {
this.cache.set(key, result);
this.cacheStats();
};
CompilationEnvironment.prototype.enqueue = function (job) {
return this.compileQueue.add(job);
};
CompilationEnvironment.prototype.findBadOptions = function (options) {
return _.filter(options, function (option) {
return !option.match(this.okOptions) || option.match(this.badOptions);
}, this);
};
exports.CompilationEnvironment = CompilationEnvironment;

223
lib/compile.js

@ -26,16 +26,15 @@ var child_process = require('child_process'),
temp = require('temp'),
path = require('path'),
httpProxy = require('http-proxy'),
LRU = require('lru-cache'),
fs = require('fs-extra'),
Promise = require('promise'), // jshint ignore:line
Queue = require('promise-queue'),
asm = require('./asm'),
utils = require('./utils'),
quote = require('shell-quote'),
logger = require('./logger').logger;
_ = require('underscore-node'),
logger = require('./logger').logger,
CompilationEnvironment = require('./compilation-env').CompilationEnvironment;
Queue.configure(Promise);
temp.track();
function periodicCleanup() {
@ -64,24 +63,9 @@ function initialise(gccProps_, compilerProps_) {
stubText = compilerProps("stubText");
}
function Compile(compilers) {
this.compilersById = {};
var self = this;
compilers.forEach(function (compiler) {
self.compilersById[compiler.id] = compiler;
});
this.okOptions = new RegExp(gccProps('optionsWhitelistRe', '.*'));
this.badOptions = new RegExp(gccProps('optionsBlacklistRe', '(?!)'));
this.cache = LRU({
max: gccProps('cacheMb') * 1024 * 1024,
length: function (n) {
return JSON.stringify(n).length;
}
});
this.cacheHits = 0;
this.cacheMisses = 0;
this.compileQueue = new Queue(gccProps("maxConcurrentCompiles", 1), Infinity);
this.multiarch = null;
function Compile(compiler, env) {
this.compiler = compiler;
this.env = env;
}
Compile.prototype.newTempDir = function () {
@ -122,24 +106,15 @@ Compile.prototype.convert6g = function (code) {
}).filter(identity).join("\n");
};
Compile.prototype.getRemote = function (compiler) {
var compilerInfo = this.compilersById[compiler];
if (!compilerInfo) return false;
if (compilerInfo.exe === null && compilerInfo.remote)
return compilerInfo.remote;
Compile.prototype.getRemote = function () {
if (this.compiler.exe === null && this.compiler.remote)
return this.compiler.remote;
return false;
};
Compile.prototype.runCompiler = function (compiler, options, inputFilename, needsMulti) {
Compile.prototype.runCompiler = function (compiler, options, inputFilename) {
var okToCache = true;
var env = {
PATH: process.env.PATH
};
if (needsMulti && this.multiarch) {
env.LIBRARY_PATH = '/usr/lib/' + this.multiarch;
env.C_INCLUDE_PATH = '/usr/include/' + this.multiarch;
env.CPLUS_INCLUDE_PATH = '/usr/include/' + this.multiarch;
}
var env = this.env.getEnv(this.compiler.needsMulti);
var child = child_process.spawn(
compiler,
options,
@ -195,20 +170,6 @@ Compile.prototype.runCompiler = function (compiler, options, inputFilename, need
});
};
Compile.prototype.getMultiarch = function () {
try {
var multi = child_process.execSync("gcc -print-multiarch").toString().trim();
if (multi) {
logger.info("Multiarch: " + multi);
this.multiarch = multi;
} else {
logger.info("No multiarch");
}
} catch (err) {
logger.warn("Unable to get multiarch: " + err);
}
};
Compile.prototype.objdump = function (outputFilename, result, maxSize, intelAsm) {
var objDumpCommand = 'objdump -d -C "' + outputFilename + '" -l --insn-width=16';
if (intelAsm) objDumpCommand += " -M intel";
@ -224,31 +185,23 @@ Compile.prototype.objdump = function (outputFilename, result, maxSize, intelAsm)
});
};
Compile.prototype.compile = function (source, compiler, options, filters) {
Compile.prototype.compile = function (source, options, filters) {
var self = this;
var optionsError = self.checkOptions(options);
if (optionsError) return Promise.reject(optionsError);
var sourceError = self.checkSource(source);
if (sourceError) return Promise.reject(sourceError);
var compilerInfo = self.compilersById[compiler];
if (!compilerInfo) {
return Promise.reject("Bad compiler " + compiler);
}
// Don't run binary for unsupported compiles, even if we're asked.
if (filters.binary && !compilerInfo.supportsBinary) {
// Don't run binary for unsupported compilers, even if we're asked.
if (filters.binary && !self.compiler.supportsBinary) {
delete filters.binary;
}
var key = compiler + " | " + source + " | " + options + " | " + JSON.stringify(filters);
var cached = self.cache.get(key);
var key = JSON.stringify({compiler: this.compiler, source: source, options: options, filters: filters});
var cached = this.env.cacheGet(key);
if (cached) {
self.cacheHits++;
self.cacheStats();
return Promise.resolve(cached);
}
self.cacheMisses++;
if (filters.binary && !source.match(stubRe)) {
source += "\n" + stubText + "\n";
@ -264,7 +217,7 @@ Compile.prototype.compile = function (source, compiler, options, filters) {
});
function filename(fn) {
if (compilerInfo.needsWine) {
if (self.compiler.needsWine) {
return 'Z:' + fn;
} else {
return fn;
@ -274,33 +227,33 @@ Compile.prototype.compile = function (source, compiler, options, filters) {
var compileToAsmPromise = tempFileAndDirPromise.then(function (info) {
var inputFilename = info.inputFilename;
var dirPath = info.dirPath;
var postProcess = compilerInfo.postProcess.filter(function (x) {
var postProcess = self.compiler.postProcess.filter(function (x) {
return x;
});
var outputFilename = path.join(dirPath, 'output.s'); // NB keep lower case as ldc compiler `tolower`s the output name
if (compilerInfo.options) {
options = options.concat(compilerInfo.options.split(" "));
if (self.compiler.options) {
options = options.concat(self.compiler.options.split(" "));
}
if (compilerInfo.intelAsm && filters.intel && !filters.binary) {
options = options.concat(compilerInfo.intelAsm.split(" "));
if (self.compiler.intelAsm && filters.intel && !filters.binary) {
options = options.concat(self.compiler.intelAsm.split(" "));
}
var compileToAsm;
var asmFlag = compilerInfo.asmFlag ? compilerInfo.asmFlag : "-S";
var outputFlag = compilerInfo.outputFlag ? compilerInfo.outputFlag : "-o";
var asmFlag = self.compiler.asmFlag ? self.compiler.asmFlag : "-S";
var outputFlag = self.compiler.outputFlag ? self.compiler.outputFlag : "-o";
if (!filters.binary) {
compileToAsm = compilerProps("compileToAsm", asmFlag).split(" ");
} else {
compileToAsm = compilerProps("compileToBinary", "").split(" ");
}
if (compilerInfo.isCl) {
if (self.compiler.isCl) {
options = options.concat(['/FAsc', '/c', '/Fa' + filename(outputFilename), '/Fo' + filename(outputFilename) + ".obj"]);
} else {
options = ['-g', outputFlag, filename(outputFilename)].concat(options);
}
options = options.concat(compileToAsm).concat([filename(inputFilename)]);
var compilerExe = compilerInfo.exe;
if (compilerInfo.needsWine) {
var compilerExe = self.compiler.exe;
if (self.compiler.needsWine) {
options = [compilerExe].concat(options);
compilerExe = gccProps("wine");
}
@ -311,52 +264,52 @@ Compile.prototype.compile = function (source, compiler, options, filters) {
}
var maxSize = gccProps("max-asm-size", 8 * 1024 * 1024);
options = options.filter(identity);
return self.runCompiler(compilerExe, options, filename(inputFilename),
compilerInfo.needsMulti).then(function (result) {
result.dirPath = dirPath;
if (result.code !== 0) {
result.asm = "<Compilation failed>";
return result;
}
if (compilerInfo.is6g) {
result.asm = self.convert6g(result.stdout);
result.stdout = [];
return Promise.resolve(result);
}
if (filters.binary && !compilerInfo.isCl) {
return self.objdump(outputFilename, result, maxSize, filters.intel);
}
return self.stat(outputFilename).then(function (stat) {
if (stat.size >= maxSize) {
result.asm = "<No output: generated assembly was too large (" + stat.size + " > " + maxSize + " bytes)>";
return self.runCompiler(compilerExe, options, filename(inputFilename))
.then(function (result) {
result.dirPath = dirPath;
if (result.code !== 0) {
result.asm = "<Compilation failed>";
return result;
}
if (postProcess.length) {
return new Promise(function (resolve) {
var postCommand = 'cat "' + outputFilename + '" | ' + postProcess.join(" | ");
child_process.exec(postCommand,
{maxBuffer: maxSize},
function (err, data) {
if (err)
data = '<No output: ' + err + '>';
result.asm = data;
resolve(result);
});
});
} else {
return self.readFile(outputFilename).then(function (contents) {
result.asm = contents.toString();
return Promise.resolve(result);
});
if (self.compiler.is6g) {
result.asm = self.convert6g(result.stdout);
result.stdout = [];
return Promise.resolve(result);
}
}, function () {
result.asm = "<No output file>";
return result;
if (filters.binary && !self.compiler.isCl) {
return self.objdump(outputFilename, result, maxSize, filters.intel);
}
return self.stat(outputFilename).then(function (stat) {
if (stat.size >= maxSize) {
result.asm = "<No output: generated assembly was too large (" + stat.size + " > " + maxSize + " bytes)>";
return result;
}
if (postProcess.length) {
return new Promise(function (resolve) {
var postCommand = 'cat "' + outputFilename + '" | ' + postProcess.join(" | ");
child_process.exec(postCommand,
{maxBuffer: maxSize},
function (err, data) {
if (err)
data = '<No output: ' + err + '>';
result.asm = data;
resolve(result);
});
});
} else {
return self.readFile(outputFilename).then(function (contents) {
result.asm = contents.toString();
return Promise.resolve(result);
});
}
}, function () {
result.asm = "<No output file>";
return result;
});
});
});
});
return self.compileQueue.add(function () {
return self.env.enqueue(function () {
return compileToAsmPromise.then(function (result) {
if (result.dirPath) {
fs.remove(result.dirPath);
@ -364,8 +317,7 @@ Compile.prototype.compile = function (source, compiler, options, filters) {
}
if (result.okToCache) {
result.asm = asm.processAsm(result.asm, filters);
self.cache.set(key, result);
self.cacheStats();
self.env.cachePut(key, result);
} else {
result.asm = {text: result.asm};
}
@ -375,13 +327,7 @@ Compile.prototype.compile = function (source, compiler, options, filters) {
};
Compile.prototype.checkOptions = function (options) {
var error = [];
var self = this;
options.forEach(function (option) {
if (!option.match(self.okOptions) || option.match(self.badOptions)) {
error.push(option);
}
});
var error = this.env.findBadOptions(options);
if (error.length > 0) return "Bad options: " + error.join(", ");
return null;
};
@ -398,24 +344,23 @@ Compile.prototype.checkSource = function (source) {
return null;
};
Compile.prototype.cacheStats = function () {
var pc = (100 * this.cacheHits) / (this.cacheMisses + this.cacheHits);
logger.info("Cache stats: " + this.cacheHits + " hits, " + this.cacheMisses + " misses (" + pc.toFixed(2) +
"%), LRU has " + this.cache.itemCount + " item(s) totalling " + this.cache.length + " bytes");
};
function CompileHandler() {
var compileObj = null;
this.compilersById = {};
this.compilerEnv = new CompilationEnvironment(gccProps);
this.setCompilers = function (compilers) {
compileObj = new Compile(compilers);
compileObj.getMultiarch();
this.compilersById = {};
_.each(compilers, function (compiler) {
this.compilersById[compiler.id] = new Compile(compiler, this.compilerEnv);
}, this);
};
var proxy = httpProxy.createProxyServer({});
this.handler = function compile(req, res, next) {
var compiler = req.body.compiler;
var remote = compileObj.getRemote(compiler);
this.handler = _.bind(function compile(req, res, next) {
var compiler = this.compilersById[req.body.compiler];
if (!compiler) return next();
var remote = compiler.getRemote();
if (remote) {
proxy.web(req, res, {target: remote}, function (e) {
logger.error("Proxy error: ", e);
@ -430,20 +375,20 @@ function CompileHandler() {
}
options = quote.parse(options).filter(identity);
var filters = req.body.filters;
compileObj.compile(source, compiler, options, filters).then(
compiler.compile(source, options, filters).then(
function (result) {
res.set('Content-Type', 'application/json');
res.end(JSON.stringify(result));
},
function (error) {
logger.error("Error: " + error.stack);
logger.error("Error: " + error);
if (typeof(error) !== "string") {
error = "Internal GCC explorer error: " + error.toString();
}
res.end(JSON.stringify({code: -1, stderr: error}));
res.end(JSON.stringify({code: -1, stderr: [{text: error}]}));
}
);
};
}, this);
}
module.exports = {

4
lib/properties.js

@ -40,10 +40,6 @@ function debug(string) {
if (propDebug) logger.info("prop: " + string);
}
function debug_show_properties() {
}
function get(base, property, defaultValue) {
var result = defaultValue;
var source = 'default';

8
package.json

@ -35,14 +35,16 @@
"winston": "2.2.x"
},
"devDependencies": {
"supervisor": "*",
"bower": "*",
"requirejs": "*",
"chai": "3.5.x",
"jshint": "*",
"mocha": "3.1.x",
"requirejs": "*",
"supervisor": "*",
"uglify-js": "*"
},
"scripts": {
"test": "make test"
"test": "mocha && make test"
},
"license": "BSD-2-Clause"
}

50
test/compilation-env.js

@ -0,0 +1,50 @@
// Copyright (c) 2012-2016, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ,
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
var should = require('chai').should();
var CompilationEnvironment = require('../lib/compilation-env').CompilationEnvironment;
var props = function (key, deflt) {
switch (key) {
case 'optionsWhitelistRe':
return '.*';
case 'optionsBlacklistRe':
return '^(-W[alp],)?((-wrapper|-fplugin.*|-specs|-load|-plugin|(@.*)|-I|-i)(=.*)?|--)$';
}
return deflt;
};
describe('Compilation environment', function () {
var ce = new CompilationEnvironment(props);
it('Should cache', function () {
should.not.exist(ce.cacheGet('foo'));
ce.cachePut('foo', 'bar');
ce.cacheGet('foo').should.equal('bar');
should.not.exist(ce.cacheGet('baz'));
});
it('Should filter bad options', function () {
ce.findBadOptions(['-O3', '-flto']).should.be.empty;
ce.findBadOptions(['-O3', '-plugin']).should.eql(['-plugin']);
});
});

94
test/test.js → test/filter-tests.js

@ -1,5 +1,3 @@
#!/usr/bin/env node
// Copyright (c) 2012-2016, Matt Godbolt
// All rights reserved.
//
@ -26,29 +24,21 @@
var fs = require('fs'), assert = require('assert');
var asm = require('../lib/asm.js');
var should = require('chai').should();
function processAsm(filename, filters) {
var file = fs.readFileSync(filename, 'utf-8');
return asm.processAsm(file, filters);
}
var cases = fs.readdirSync('./cases')
var cases = fs.readdirSync(__dirname + '/cases')
.filter(function (x) {
return x.match(/\.asm$/)
})
.map(function (x) {
return './cases/' + x;
return __dirname + '/cases/' + x;
});
var failures = 0;
function assertEq(a, b, context) {
if (a != b) {
console.log("Fail: ", a, " != ", b, context);
failures++;
}
}
function bless(filename, output, filters) {
var result = processAsm(filename, filters);
fs.writeFileSync(output, JSON.stringify(result, null, 2));
@ -74,33 +64,26 @@ function testFilter(filename, suffix, filters) {
try {
file = fs.readFileSync(expected, 'utf-8');
} catch (e) {
console.log("Skipping non-existent test case " + expected);
return;
}
}
if (json) {
file = JSON.parse(file);
} else {
file = file.split(/\r?\n/);
}
assertEq(file.length, result.length, expected);
var count = Math.min(file.length, result.length);
for (var i = 0; i < count; ++i) {
it(filename, function () {
if (json) {
try {
assert.deepEqual(file[i], result[i]);
} catch (e) {
console.log("########### got ##########");
dump(result);
console.log("########### expected ##########");
dump(file);
throw new Error(e + " at " + expected + ":" + (i + 1));
}
file = JSON.parse(file);
} else {
var lineExpected = result[i].text;
assertEq(file[i], lineExpected, expected + ":" + (i + 1));
file = file.split(/\r?\n/);
}
}
result.length.should.equal(file.length);
var count = Math.min(file.length, result.length);
for (var i = 0; i < count; ++i) {
if (json) {
file[i].should.deep.equal(result[i]);
} else {
var lineExpected = result[i].text;
file[i].should.deep.equal(lineExpected);//, expected + ":" + (i + 1));
}
}
});
}
// bless("cases/cl-regex.asm", "cases/cl-regex.asm.directives.labels.comments.json", {directives: true, labels: true, commentOnly: true});
// bless("cases/cl-regex.asm", "cases/cl-regex.asm.dlcb.json", {directives: true, labels: true, commentOnly: true, binary:true});
@ -108,23 +91,28 @@ function testFilter(filename, suffix, filters) {
// bless("cases/cl64-sum.asm", "cases/cl64-sum.asm.dlcb.json", {directives: true, labels: true, commentOnly: true, binary:true});
// bless("cases/avr-loop.asm", "cases/avr-loop.asm.directives.labels.comments.json", {directives: true, labels: true, commentOnly: true});
cases.forEach(function (x) {
testFilter(x, ".directives", {directives: true})
});
cases.forEach(function (x) {
testFilter(x, ".directives.labels",
{directives: true, labels: true})
});
cases.forEach(function (x) {
testFilter(x, ".directives.labels.comments",
{directives: true, labels: true, commentOnly: true})
});
cases.forEach(function (x) {
testFilter(x, ".dlcb",
{directives: true, labels: true, commentOnly: true, binary: true})
describe('Filter test cases', function () {
describe('Directive filters', function () {
cases.forEach(function (x) {
testFilter(x, ".directives", {directives: true})
});
});
describe('Directives and labels together', function () {
cases.forEach(function (x) {
testFilter(x, ".directives.labels",
{directives: true, labels: true})
});
});
describe('Directives, labels and comments', function () {
cases.forEach(function (x) {
testFilter(x, ".directives.labels.comments",
{directives: true, labels: true, commentOnly: true})
});
});
describe('Directives, labels, comments and binary mode', function () {
cases.forEach(function (x) {
testFilter(x, ".dlcb",
{directives: true, labels: true, commentOnly: true, binary: true})
});
});
});
if (failures) {
console.log(failures + " failures");
process.exit(1);
}
Loading…
Cancel
Save