@openscope/validator
Version:
A CLI used to validate an airport definition file used in the [openscope](http://openscope.co) ATC Simulator
271 lines (207 loc) • 9.24 kB
JavaScript
const expect = require('chai').expect
const sinon = require('sinon');
const ValidatorAbstract = require('../ValidatorAbstract');
const SidsValidator = require('../SidsValidator');
const SpawnPatternsValidator = require('../SpawnPatternsValidator');
const WindValidator = require('../WindValidator');
const airportKseaMock = require('./_mock/airportKseaMock');
const ERROR_MESSAGE = require('./_mock/errorMessageMock');
const invalidSidMock = {
SUMMA1: {
rwy: {
KSEA16L: ['NEVJO'],
KSEA16C: ['NEVJO'],
KSEA16R: ['NEVJO'],
KSEA34L: [['NEZUG', 'A40+'], '^_NEZUG070PAE139', '_SUMMA326017'],
KSEA34C: [['NEZUG', 'A40+'], '^_NEZUG070PAE139', '_SUMMA326017'],
KSEA34R: [['NEZUG', 'A40+'], '^_NEZUG070PAE139', '_SUMMA326017']
},
exitPoints: {
BKE: ['SUMMA', 'BKE'],
LKV: ['SUMMA', 'LKV'],
SUMMA: ['SUMMA']
},
draw: [
['NEVJO', 'SUMMA'],
['NEZUG', '_NEZUG070PAE139', '_SUMMA326017', 'SUMMA'],
['SUMMA', 'LKV*'],
['SUMMA*', 'BKE*']
]
}
};
class InvalidValidator extends ValidatorAbstract {
constructor() {
super('threeve', null);
}
}
describe('ValidatorAbstract', () => {
describe('invalid data', () => {
it('should not throw with invalid data', () => {
expect(() => new ValidatorAbstract()).to.not.throw();
});
it('should register an error when `#_json` is `undefined`', () => {
const validator = new ValidatorAbstract('base');
expect(validator.errors[0].message).to.eq(`${ERROR_MESSAGE.UNDEFINED.BASE.replace('{KEY}', 'base')}`);
});
it('should register an error when `#_requiredKeys` is `undefined`', () => {
const validator = new ValidatorAbstract('threeve', airportKseaMock);
expect(validator.errors[0].message).to.eq(`${ERROR_MESSAGE.UNDEFINED.BASE.replace('{KEY}', 'base')}`);
});
});
describe('valid data', () => {
it('should not throw with valid data', () => {
expect(() => new ValidatorAbstract('base', airportKseaMock)).not.to.throw();
});
it('should not call `.registerError` when no error exists', () => {
const windValidator = new WindValidator(airportKseaMock.wind);
const registerErrorSpy = sinon.spy(windValidator, 'registerError');
windValidator.validate();
expect(registerErrorSpy.callCount).to.eq(0);
});
});
describe('.validate()', () => {
it('should throw', () => {
const validator = new ValidatorAbstract();
expect(() => validator.validate()).to.throw();
});
});
describe('.registerError()', () => {
it('should throw when it does not receive a MessageType', () => {
const validator = new ValidatorAbstract();
expect(() => validator.registerError({})).to.throw();
});
});
describe('when extended', () => {
describe('and passed invalid data', () => {
it('it should not throw', () => {
expect(() => new InvalidValidator()).to.not.throw();
});
it('should return early from .validateObj()', () => {
const validator = new InvalidValidator();
const validateSingleSpy = sinon.spy(validator, 'validateSingle');
validator.validateObj();
expect(validateSingleSpy.notCalled).to.be.true;
});
it('should return early from .validateList()', () => {
const validator = new InvalidValidator();
const validateSingleSpy = sinon.spy(validator, 'validateSingle');
validator.validateList();
expect(validateSingleSpy.notCalled).to.be.true;
});
});
});
describe('when passed valid data', () => {
describe('and `#_data` is an dict', () => {
let sidsValidator;
beforeEach(() => {
sidsValidator = new SidsValidator(airportKseaMock.sids, airportKseaMock.fixes);
});
afterEach(() => {
sidsValidator = null;
});
it('should call `.validateObj()` when `#_data` is an dict', () => {
const validateObjSpy = sinon.spy(sidsValidator, 'validateObj');
sidsValidator.validate();
expect(validateObjSpy.callCount).to.eq(1);
});
it('should call `.validateItem()` with each item in the dict', () => {
const _validateItemSpy = sinon.spy(sidsValidator, '_validateItem');
sidsValidator.validateObj();
expect(_validateItemSpy.callCount).to.eq(7);
});
it('should provide a contextual error message for the `#key` that failed', () => {
const expectedResult = 'Fail: `sids` - `SUMMA1` is missing the following required keys: icao, name, body';
const validator = new SidsValidator(invalidSidMock, airportKseaMock.fixes);
validator.validate();
expect(validator.errors[0].message).to.eq(expectedResult);
});
});
describe('and `#_data` is an array', () => {
let spawnPatternsValidator;
beforeEach(() => {
spawnPatternsValidator = new SpawnPatternsValidator(airportKseaMock.spawnPatterns);
});
afterEach(() => {
spawnPatternsValidator = null;
});
it('should call `.validateList()` when `#_data` is an array', () => {
const validateListSpy = sinon.spy(spawnPatternsValidator, 'validateList');
spawnPatternsValidator.validate();
expect(validateListSpy.callCount).to.eq(1);
});
it('should call `._validateItem()` with each item in the array', () => {
const _validateItemSpy = sinon.spy(spawnPatternsValidator, '_validateItem');
spawnPatternsValidator.validate();
expect(_validateItemSpy.callCount).to.eq(12);
});
});
describe('and `#_data` is an object', () => {
let windValidator;
beforeEach(() => {
windValidator = new WindValidator(airportKseaMock.wind);
});
afterEach(() => {
windValidator = null;
});
it('should call `.validateSingle()` when `#_data` is an object', () => {
const validateSingleSpy = sinon.spy(windValidator, 'validateSingle');
windValidator.validate();
expect(validateSingleSpy.callCount).to.eq(1);
});
});
describe('`#_name` and `_#key`', () => {
let spawnPatternsValidator;
let windValidator;
beforeEach(() => {
spawnPatternsValidator = new SpawnPatternsValidator({});
windValidator = new WindValidator({});
});
afterEach(() => {
spawnPatternsValidator = null;
windValidator = null;
});
describe('when passed as lowercase', () => {
it('should be stored as lowercase', () => {
expect(windValidator._name).to.eq('wind');
});
it('should generate a `#_key` as UPPERCASE', () => {
expect(windValidator.keyName).to.eq('WIND');
});
});
describe('when passed as camelCase', () => {
it('should be stored as camelCase', () => {
expect(spawnPatternsValidator._name).to.eq('spawnPatterns');
});
it('should generate a `#_key` as CONSTANT_CASE', () => {
expect(spawnPatternsValidator.keyName).to.eq('SPAWN_PATTERNS');
});
});
});
describe('.validateInterface()', () => {
describe('with invalid data', () => {
it('adds the correct error to `_#errors`', () => {
const expectedResult = 'Invalid value "" supplied to IWind/angle: Number';
const invalidWindMock = {
angle: '',
speed: 1
};
const validator = new WindValidator(invalidWindMock);
validator.validate();
expect(validator.errors[0].message).to.eq(expectedResult);
});
});
describe('with valid data', () => {
it('does not change the length of `#_errors`', () => {
const windMock = {
angle: 2,
speed: 1
};
const validator = new WindValidator(windMock);
validator.validate();
expect(validator.errors.length).to.eq(0);
});
});
});
});
});