swagmock-allof
Version:
Mock data generator for swagger api
247 lines (228 loc) • 7.38 kB
JavaScript
;
const Chance = require('chance').Chance();
const Format = require('./format');
const Randexp = require('randexp').randexp;
const mock = (schema, useExample) => {
let mock;
if (schema) {
let type = schema.type || findType(schema);
let example = schema.examples || schema.example;
/**
* Get the mock generator from the `type` of the schema
*/
if (example && useExample) {
mock = example;
} else {
const generator = Generators[type];
if (generator) {
mock = generator.call(null, schema, useExample);
}
}
}
return mock;
};
const objectMock = ({ properties, additionalProperties, allOf }, useExample ) => {
let mockObj = {};
if (properties) {
Object.keys(properties).forEach(function (key) {
mockObj[key] = mock(properties[key], useExample);
});
/**
* In the absense of `properties`, check if `additionalProperties` is defined or not.
* (If additionalProperties is an object, that object is a schema that will be used to validate
* any additional properties not listed in properties.)
*
* If present, use this to generate mocks.
*/
} else if (additionalProperties) {
//Create a random property
mockObj[Chance.word()] = mock(additionalProperties, useExample);
}
/**
* Check if `allOf` is defined. If so, iterate through all of the objects mentioned
* in the array and merge them with this result.
*/
if (allOf) {
allOf.forEach((subObject) => {
Object.assign(mockObj, mock(subObject, useExample));
});
}
return mockObj;
};
/**
* Generates a mock `array` data of `items`
* Supports: `minItems` and `maxItems`
* TODO: Implement `uniqueItems`
*/
const arrayMock = ({ items, minItems, maxItems }, useExample) => {
let min;
let max;
let numItems;
let arr = [];
if (items) {
//Use the min as the base
min = minItems || 1;
if (maxItems) {
//If min is greater than max, use min as max.
max = (maxItems < min) ? min : maxItems;
} else {
//If max is not defined, use min as max.
max = min;
}
//Find the number of items with min and max boundary parameters.
numItems = Chance.integer({
min: min,
max: max
});
for (let i = 0; i < numItems; i++) {
arr.push(mock(items, useExample));
}
}
return arr;
};
/**
* Generates a mock `integer` value
* Supports `minimum`, `maximum`, `exclusiveMinimum` and `exclusiveMaximum`
* TODO - Validate `minimum` and `maximum` values
*/
const integerMock = schema => {
let opts = {};
let intmock;
/**
* If `enum` is defined for the property
*/
if (schema.enum && schema.enum.length > 0) {
return enumMock(schema);
}
if (Number.isInteger(schema.minimum)) {
opts.min = (schema.exclusiveMinimum) ? schema.minimum + 1 : schema.minimum;
}
if (Number.isInteger(schema.maximum)) {
opts.max = (schema.exclusiveMaximum) ? schema.maximum - 1 : schema.maximum;
}
//Generate a number that is multiple of schema.multipleOf
if (Number.isInteger(schema.multipleOf) && schema.multipleOf > 0) {
//Use the min/muplilier as the min number
//Use default min as 1 if min is not properly set.
opts.min = (Number.isInteger(opts.min)) ? (Math.ceil(opts.min / schema.multipleOf)) : 1;
//Use the max/muplilier as the new max value
//Use a default - min + 10 - if max value is not properly set.
opts.max = (Number.isInteger(opts.max)) ? (Math.floor(opts.max / schema.multipleOf)) : (opts.min + 10);
intmock = Chance.integer(opts);
intmock = intmock * schema.multipleOf;
} else {
intmock = Chance.integer(opts);
}
return intmock;
};
/**
* Generates a mock `number` value
* Supports `minimum`, `maximum`, `exclusiveMinimum` and `exclusiveMaximum`
* TODO - Validate `minimum` and `maximum` values
*/
const numberMock = schema => {
let opts = {};
let nummock;
/**
* If `enum` is defined for the property
*/
if (schema.enum && schema.enum.length > 0) {
return enumMock(schema);
}
if (Number.isFinite(schema.minimum)) {
opts.min = (schema.exclusiveMinimum) ? schema.minimum + 0.1 : schema.minimum;
}
if (Number.isFinite(schema.maximum)) {
opts.max = (schema.exclusiveMaximum) ? schema.maximum - 0.1 : schema.maximum ;
}
//Generate a number that is multiple of schema.multipleOf
if (Number.isFinite(schema.multipleOf) && schema.multipleOf > 0) {
//Use the min/muplilier as the min number
//Use default min as 1 if min is not properly set
opts.min = (Number.isFinite(opts.min)) ? (Math.ceil(opts.min / schema.multipleOf)) : 1;
//Use the max/muplilier as the new max value
//Use a default - min + 10 - if max value is not properly set.
opts.max = (Number.isFinite(opts.max)) ? (Math.floor(opts.max / schema.multipleOf)) : (opts.min + 10);
nummock = Chance.integer(opts);
nummock = nummock * schema.multipleOf;
} else {
nummock = Chance.floating(opts);
}
return nummock;
};
const booleanMock = schema => {
/**
* If `enum` is defined for the property
*/
if (schema.enum && schema.enum.length > 0) {
return enumMock(schema);
}
return Chance.bool();
};
/**
* Geneartes a mock `string` value
* Supports: `minLength`, `maxLength`, `enum`, `date`, and `date-time`
*
*/
const stringMock = schema => {
let mockStr;
let opts = {};
let minLength = schema.minLength || 1;
let maxLength = schema.maxLength || minLength + 10;
opts.min = minLength;
opts.max = maxLength;
if (schema.enum && schema.enum.length > 0) {
/**
* If `enum` is defined for the property
*/
mockStr = enumMock(schema);
} else if (schema.pattern) {
/**
* If `pattern` is defined for the property
*/
mockStr = Randexp(schema.pattern);
} else if(Format[schema.format]) {
/**
* If a `format` is defined for the property
*/
mockStr = Format[schema.format].call(null, schema);
} else {
mockStr = Chance.string({
length: Chance.integer(opts),
alpha: true //Use only alpha characters
});
}
return mockStr;
};
const enumMock = schema => {
let len = schema.enum.length;
let opts = {
min: 0,
max: len - 1
};
return schema.enum[Chance.integer(opts)];
};
const fileMock = () => {
return Chance.file();
};
//Find out the type based on schema props
//(This is not a complete list or full proof solution)
const findType = schema => {
let type = 'object';// Use 'object' as the default type
if (schema.pattern) {
type = 'string';
} else if (schema.items) {
type = 'array';
}
return type;
};
const Generators = module.exports = {
object: objectMock,
array: arrayMock,
string: stringMock,
integer: integerMock,
number: numberMock,
boolean: booleanMock,
file: fileMock,
mock
};