UNPKG

json-schema-test-suite

Version:

Exposes JSON Schema Test Suite as a Node.js package

155 lines (130 loc) 5.31 kB
var _ = require('lodash'), fs = require('fs'), path = require('path'); module.exports = { testSync: testSync, loadSync: loadTestSuiteSync, draft3: function(filter) { return loadTestSuiteSync({ filter: filter, draft: 'draft3' }); }, draft4: function(filter) { return loadTestSuiteSync({ filter: filter, draft: 'draft4' }); }, loadAllSync: function(draft) { return loadTestSuiteSync({ draft: draft }); }, loadRequiredSync: function (draft) { return loadTestSuiteSync({ filter: requiredOnlyFilter, draft: draft }); }, loadOptionalSync: function (draft) { return loadTestSuiteSync({ filter: optionalOnlyFilter, draft: draft }); }, requiredOnlyFilter: requiredOnlyFilter, optionalOnlyFilter: optionalOnlyFilter }; /** * convenience filter for required tests */ function requiredOnlyFilter(file, parent, optional) { return !optional; } /** * convenience filter for optional tests */ function optionalOnlyFilter(file, parent, optional) { return optional; } /** * Returns tests specified by draft and filtered by filter argument * @param filter a function that returns true if the file (or directory) * should be included; the function is passed 3 arguments * (file, parent, optional); optional is true if the file is * the optional directory or any file under it. * see exported requiredOnlyFilter * @param options an object with the following properties * draft: 'draft3' | 'draft4' (default) * @returns [] */ function loadTestSuiteSync(options) { var config = options ? _.clone(options) : {}; config.path = path.join(__dirname, 'tests', config.draft || 'draft4'); return loadTestsSync(config); } /** * Returns test suite array * @param config an object with the following properties * path: full path to the current test directory * filter: (optional) a function that returns true if the file (or directory) * should be included; the function is passed 3 arguments * (file, parent, optional); optional is true if the file is * the optional directory or any file under it. * parent: the parent directory (undefined for the root of the tests directory) * optional: set to true when recursing into optional directory * @returns [] */ function loadTestsSync(config) { var filter = config.filter; var testPath = config.path; var parent = config.parent; var optional = !!config.optional; if (!testPath) throw new Error('missing path to test directory'); var tests = []; var testFiles = fs.readdirSync(testPath); testFiles.filter(function (file) { // optional might not be set at this point, so need to check if the file is named 'optional' // (meaning it's the actual optional directory) return filter ? filter(file, parent, optional || file == 'optional') : true; }).forEach(function (file) { var filePath = path.join(testPath, file); var stats = fs.lstatSync(filePath); if (stats.isDirectory()) { // once optional is set after entering an 'optional' directory, no need to reevaluate tests = tests.concat(loadTestsSync({ filter: filter, path: path.join(testPath, file), parent: parent, optional: optional || file == 'optional' })); } else if (stats.isFile()) { var end = file.indexOf('.json'); if (end > 0) { tests.push({ name: file.substring(0, end), file: file, path: filePath, optional: optional, schemas: require(filePath) }); } } }); return tests; } /** * Applies the validator function against all the tests that match the draft version and pass the filter * @param validatorFactory a function that takes 2 arguments (schema, options); if the schema argument is * a string, it will parsed as JSON. The function should returns an object with a validate method * that takes 1 argument (json). The validate method should return an object; if there were * validation errors, the object should have a valid property that is true or false depending on * whether there are validation errors, and an errors property with an array for the validation * errors, if any. The schema and the JSON test data will be obtained from the test suite. * @param options an optional options argument that will be provided to validatorFactory * @param filter a function that returns true if the file (or directory) * should be included; the function is passed 3 arguments * (file, parent, optional); optional is true if the file is * the optional directory or any file under it. * see exported requiredOnlyFilter * @param draft 'draft3' | 'draft4' (default) */ function testSync(validatorFactory, options, filter, draft) { if (typeof options == 'function') { draft = filter; filter = options; options = {}; } var tests = loadTestSuiteSync({ filter: filter, draft: draft }); tests.forEach(function (test) { test.schemas.forEach(function (schema) { var validator = validatorFactory(schema.schema, options); schema.tests.forEach(function (testCase) { testCase.result = validator.validate(testCase.data); }); }); }); return tests; }