node-mock-server
Version:
File based Node REST API mock server
526 lines (437 loc) • 9.82 kB
JavaScript
'use strict';
var extend = require('util')._extend;
var validatorLog = require('./ValidatorLog');
var Utils = require('./Utils');
/**
*
* @class ValidatorDataSchema
* @namespace ValidatorDataSchema
* @param {object} options
* @constructor
*
* Swagger importer
*/
function ValidatorDataSchema(options) {
this.init(options);
}
ValidatorDataSchema.prototype = extend(ValidatorDataSchema.prototype, Utils.prototype);
ValidatorDataSchema.prototype = extend(ValidatorDataSchema.prototype, {
constructor: ValidatorDataSchema,
_defaults: {
schema: undefined,
data: undefined,
},
/**
*
* @method init
* called by constructor
* @param {object} options
* @public
*/
init: function (options) {
var _validation = {};
var cleanedPath = this.cleanPath(options, options.filePathData);
options = extend(this._defaults, options || {});
this._options = options;
this._isValid = true;
this._schema = this._options.schema;
this._data = this._options.data;
this._path = this._options.path;
this._expected = this._options.expected;
this._schemaMap = {};
this._invalidCounter = 0;
if (!this._schema || typeof this._schema !== 'object') {
this._isValid = false;
validatorLog.error('<code>options.schema</code> can\'t be empty!');
}
if (!this._data || typeof this._data !== 'object') {
this._isValid = false;
}
this._mapSchema(this._schema);
this._mapData(this._data);
_validation.validation = {};
_validation.validation[this._expected] = {};
_validation.validation[this._expected].counter = this._invalidCounter;
this.setMethodStore(this._path, _validation);
if (this._invalidCounter > 0) {
validatorLog.error('Mock data in file <code>' + cleanedPath + '</code> are invalid! ' +
'<span class="label label-danger">' + this._invalidCounter + '</span> invalid values found.');
return false;
}
validatorLog.success('Mock data in file <code>' + cleanedPath + '</code> are valid!');
return true;
},
/**
* @method _mapSchema
* @param {object|Array} schema
* @returns {void}
* @private
*/
_mapSchema: function (schema) {
this._mapSchemaUnknown({
data: schema,
path: [],
refs: [],
});
},
/**
* @method _mapSchemaUnknown
* @param {object} opt
* @param {Array} opt.path
* @param {object} opt.data
* @param {Array} opt.refs
* @returns {Boolean} isMapped
* @private
*/
_mapSchemaUnknown: function (opt) {
if (opt.data instanceof Array) {
if (opt.data.length > 0) {
this._mapSchemaArray({
data: opt.data[0],
path: opt.path,
refs: opt.refs,
});
}
return true;
}
if (typeof opt.data === 'object') {
this._mapSchemaObject({
data: opt.data,
path: opt.path,
refs: opt.refs,
});
return true;
}
return false;
},
/**
* @method _mapSchemaArray
* @param {object} opt
* @param {Array} opt.path
* @param {*} opt.data
* @param {Array} opt.refs
* @returns {void}
* @private
*/
_mapSchemaArray: function (opt) {
this._setTmpSchemaObj({
path: opt.path.slice(),
type: 'array',
refs: opt.refs,
});
var path = opt.path.slice();
var newPath;
path.push('[]');
if (typeof opt.data !== 'object' || opt.data instanceof Array) {
newPath = path.slice();
if (opt.data instanceof Array) {
if (opt.data.length > 0) {
this._mapSchemaArray({
data: opt.data[0],
path: newPath,
refs: opt.refs,
});
}
return;
}
this._mapSchemaString({
data: opt.data,
path: newPath,
refs: opt.refs,
});
return;
}
this.forIn(opt.data, function (key, value) {
newPath = path.slice();
if (
this._mapSchemaUnknown({
data: value,
path: newPath,
refs: opt.refs,
})
) {
return;
}
newPath.push(key);
this._mapSchemaString({
data: value,
path: newPath,
refs: opt.refs,
});
}.bind(this));
},
/**
* @method _mapSchemaObject
* @param {object} opt
* @param {Array} opt.path
* @param {object} opt.data
* @param {Array} opt.refs
* @returns {void}
* @private
*/
_mapSchemaObject: function (opt) {
this._setTmpSchemaObj({
path: opt.path.slice(),
type: 'object',
refs: opt.refs,
});
this.forIn(opt.data, function (key, value) {
var newPath = opt.path.slice();
newPath.push(key);
if (
this._mapSchemaUnknown({
data: value,
path: newPath,
refs: opt.refs,
})
) {
return;
}
this._mapSchemaString({
data: value,
path: newPath,
refs: opt.refs,
});
return true;
}.bind(this));
},
/**
* @method _mapSchemaString
* @param {object} opt
* @param {Array} opt.path
* @param {String} opt.data
* @param {Array} opt.refs
* @returns {void}
* @private
*/
_mapSchemaString: function (opt) {
var regResult = (/(^\$ref-)(.*)/).exec(opt.data);
if (regResult !== null && regResult.length > 2) {
var ref = this._getRef(regResult[2]);
var refs = opt.refs.slice();
var found1 = refs.indexOf(regResult[2]);
refs.push(regResult[2]);
if (found1 >= 0) {
if (refs.indexOf(regResult[2], found1) >= 0) {
return;
}
}
if (ref instanceof Array) {
if (ref.length > 0) {
this._mapSchemaArray({
data: ref[0],
path: opt.path,
refs: refs,
});
}
return;
}
if (typeof ref === 'object') {
this._mapSchemaObject({
data: ref,
path: opt.path,
refs: refs,
});
return;
}
return;
}
this._setTmpSchemaObj({
path: opt.path,
type: this._mapType(opt.data),
});
},
/**
* @method _getRef
* @param {String} refName
* @returns {Object|Array}
* @private
*/
_getRef: function (refName) {
try {
return JSON.parse(this.readFile(this._options.restPath + '/_DTO/' + refName + '.json'));
} catch (err) {
return {};
}
},
/**
* @method _mapData
* @param {object} data
* @returns {void}
* @private
*/
_mapData: function (data) {
if (data instanceof Array) {
this._mapDataArray({
data: data,
path: [],
});
} else if (typeof data === 'object') {
this._mapDataObject({
data: data,
path: [],
});
}
},
/**
* @method _mapDataObject
* @param {object} opt
* @param {Array} opt.path
* @param {Object|Array} opt.data
* @returns {void}
* @private
*/
_mapDataObject: function (opt) {
this.forIn(opt.data, function (key, value) {
var newPath = opt.path.slice();
var type = this._getType(value);
var isObject = (type === 'object');
var isArray = (type === 'array');
newPath.push(key);
if (isObject || isArray) {
this._validateObject({
path: newPath,
type: type,
});
} else {
this._validateObject({
path: newPath,
type: type,
value: value,
});
}
if (isObject) {
this._mapDataObject({
data: value,
path: newPath,
});
return;
}
if (isArray) {
this._mapDataArray({
data: value,
path: newPath,
});
}
}.bind(this));
},
/**
* @method _validateObject
* @param {object} opt
* @param {Array} opt.path
* @param {String} opt.type
* @param {*} opt.value
* @returns {void}
* @private
*/
_validateObject: function (opt) {
var keyName = this._getSchemaKeyName(opt);
var item = this._schemaMap[keyName];
var pathStr = opt.path.join('.');
if (!item) {
validatorLog.error('No schema definition for: <code>' + pathStr + '</code> found, ' +
'please check you schema and/or mock file!');
this._invalidCounter += 1;
return;
}
if (item !== opt.type) {
validatorLog.error('invalid type for: <code>' + pathStr + '</code> ' +
'with value <code>' + opt.value + '</code> found! ' +
'Value needs to by type of <code>' + item + '</code>.'
);
this._invalidCounter += 1;
}
},
/**
* @method _setTmpSchemaObj
* @param {object} opt
* @param {Array} opt.path
* @param {String} opt.type
* @returns {void}
* @private
*/
_setTmpSchemaObj: function (opt) {
if (!(opt.path instanceof Array) || opt.path.length < 1) {
return;
}
this._schemaMap[this._getSchemaKeyName(opt)] = opt.type;
},
/**
* @method _getSchemaKeyName
* @param {object} opt
* @param {Array} opt.path
* @returns {String}
* @private
*/
_getSchemaKeyName: function (opt) {
var fileName = opt.path.join('.');
fileName = fileName.trim();
return this._getHashCode(fileName);
},
/**
* @method _getHashCode
* @param {String} s
* @returns {String}
* @private
*/
_getHashCode: function (s) {
// eslint-disable-next-line
return s.split('').reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);
},
/**
* @method _mapDataArray
* @param {object} opt
* @param {Array} opt.path
* @param {Object|Array} opt.data
* @returns {void}
* @private
*/
_mapDataArray: function (opt) {
var path = opt.path.slice();
path.push('[]');
this.for(opt.data, function (value) {
var newPath = path.slice();
var type = this._getType(value);
if (type === 'object') {
this._mapDataObject({
data: value,
path: newPath,
});
return;
}
if (type === 'array') {
this._mapDataArray({
data: value,
path: newPath,
});
}
}.bind(this));
},
/**
* @method _getType
* @param {*} value
* @returns {string} type
* @private
*/
_getType: function (value) {
if (value instanceof Array) {
return 'array';
}
return (typeof value).toLowerCase();
},
/**
* @method _mapType
* @param {*} type
* @returns {string} type
* @private
*/
_mapType: function (type) {
switch (type) {
case 'integer': return 'number';
case 'float': return 'number';
case 'bigdezimal': return 'number';
default: return type;
}
},
});
module.exports = ValidatorDataSchema;