Validate solcoverjs with json schema (#403)
parent
556d2d2e58
commit
ee72e8d66d
@ -0,0 +1,72 @@ |
||||
const Validator = require('jsonschema').Validator; |
||||
const AppUI = require('./ui').AppUI; |
||||
const util = require('util') |
||||
|
||||
|
||||
function isFunction(input){ |
||||
|
||||
} |
||||
|
||||
Validator.prototype.customFormats.isFunction = function(input) { |
||||
return typeof input === "function" |
||||
}; |
||||
|
||||
const configSchema = { |
||||
id: "/solcoverjs", |
||||
type: "object", |
||||
properties: { |
||||
|
||||
client: {type: "object"}, |
||||
cwd: {type: "string"}, |
||||
host: {type: "string"}, |
||||
|
||||
|
||||
originalContractsDir: {type: "string"}, |
||||
port: {type: "number"}, |
||||
providerOptions: {type: "object"}, |
||||
silent: {type: "boolean"}, |
||||
|
||||
// Hooks:
|
||||
onServerReady: {type: "function", format: "isFunction"}, |
||||
onTestComplete: {type: "function", format: "isFunction"}, |
||||
onIstanbulComplete: {type: "function", format: "isFunction"}, |
||||
|
||||
// Arrays
|
||||
skipFiles: { |
||||
type: "array", |
||||
items: {type: "string"} |
||||
}, |
||||
|
||||
istanbulReporter: { |
||||
type: "array", |
||||
items: {type: "string"} |
||||
}, |
||||
}, |
||||
}; |
||||
|
||||
class ConfigValidator { |
||||
constructor(){ |
||||
this.validator = new Validator(); |
||||
this.validator.addSchema(configSchema); |
||||
this.ui = new AppUI(); |
||||
} |
||||
|
||||
validate(config){ |
||||
let result = this.validator.validate(config, configSchema); |
||||
|
||||
if (result.errors.length){ |
||||
let msg; |
||||
const option = `"${result.errors[0].property.replace('instance.', '')}"`; |
||||
|
||||
(result.errors[0].argument === 'isFunction') |
||||
? msg = `${option} is not a function` |
||||
: msg = `${option} ${result.errors[0].message}`; |
||||
|
||||
throw new Error(this.ui.generate('config-fail', [msg])); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
module.exports = ConfigValidator; |
@ -0,0 +1,137 @@ |
||||
const assert = require('assert'); |
||||
const util = require('util'); |
||||
const ConfigValidator = require('./../../lib/validator'); |
||||
|
||||
describe('config validation', () => { |
||||
let validator; |
||||
let solcoverjs; |
||||
|
||||
before(() => validator = new ConfigValidator()); |
||||
beforeEach(() => solcoverjs = {}); |
||||
|
||||
it('validates an empty config', function() { |
||||
assert(validator.validate(solcoverjs), '{} should be valid'); |
||||
}) |
||||
|
||||
it('validates config with unknown options', function(){ |
||||
solcoverjs.unknown_option = 'hello'; |
||||
assert(validator.validate(solcoverjs), '.cwd string should be valid') |
||||
}) |
||||
|
||||
it('validates the "string" options', function(){ |
||||
const options = [ |
||||
"cwd", |
||||
"host", |
||||
"originalContractsDir", |
||||
] |
||||
|
||||
options.forEach(name => { |
||||
// Pass
|
||||
solcoverjs = {}; |
||||
solcoverjs[name] = "a_string"; |
||||
assert(validator.validate(solcoverjs), `${name} string should be valid`) |
||||
|
||||
// Fail
|
||||
solcoverjs[name] = 0; |
||||
try { |
||||
validator.validate(solcoverjs); |
||||
assert.fail() |
||||
} catch (err){ |
||||
assert(err.message.includes(`"${name}" is not of a type(s) string`), err.message); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
it('validates the "object" options', function(){ |
||||
const options = [ |
||||
"client", |
||||
"providerOptions", |
||||
] |
||||
|
||||
options.forEach(name => { |
||||
// Pass
|
||||
solcoverjs = {}; |
||||
solcoverjs[name] = {a_property: 'a'}; |
||||
assert(validator.validate(solcoverjs), `${name} object should be valid`) |
||||
|
||||
// Fail
|
||||
solcoverjs[name] = 0; |
||||
try { |
||||
validator.validate(solcoverjs); |
||||
assert.fail() |
||||
} catch (err){ |
||||
assert(err.message.includes(`"${name}" is not of a type(s) object`), err.message); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
it('validates the "number" options', function(){ |
||||
const options = [ |
||||
"port", |
||||
] |
||||
|
||||
options.forEach(name => { |
||||
// Pass
|
||||
solcoverjs = {}; |
||||
solcoverjs[name] = 0; |
||||
assert(validator.validate(solcoverjs), `${name} number should be valid`) |
||||
|
||||
// Fail
|
||||
solcoverjs[name] = "a_string"; |
||||
try { |
||||
validator.validate(solcoverjs); |
||||
assert.fail() |
||||
} catch (err){ |
||||
assert(err.message.includes(`"${name}" is not of a type(s) number`), err.message); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
it('validates string array options', function(){ |
||||
const options = [ |
||||
"skipFiles", |
||||
"istanbulReporter", |
||||
] |
||||
|
||||
options.forEach(name => { |
||||
// Pass
|
||||
solcoverjs = {}; |
||||
solcoverjs[name] = ['a_string']; |
||||
assert(validator.validate(solcoverjs), `${name} string array should be valid`) |
||||
|
||||
// Fail
|
||||
solcoverjs[name] = "a_string"; |
||||
try { |
||||
validator.validate(solcoverjs); |
||||
assert.fail() |
||||
} catch (err){ |
||||
assert(err.message.includes(`"${name}" is not of a type(s) array`), err.message); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
it('validates function options', function(){ |
||||
|
||||
const options = [ |
||||
"onServerReady", |
||||
"onTestComplete", |
||||
"onIstanbulComplete", |
||||
] |
||||
|
||||
options.forEach(name => { |
||||
// Pass
|
||||
solcoverjs = {}; |
||||
solcoverjs[name] = async (a,b) => {}; |
||||
assert(validator.validate(solcoverjs), `${name} string array should be valid`) |
||||
|
||||
// Fail
|
||||
solcoverjs[name] = "a_string"; |
||||
try { |
||||
validator.validate(solcoverjs); |
||||
assert.fail() |
||||
} catch (err){ |
||||
assert(err.message.includes(`"${name}" is not a function`), err.message); |
||||
} |
||||
}); |
||||
}); |
||||
}); |
Loading…
Reference in new issue