| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- import {expect} from 'chai';
- import {chai} from '../../../chai.js';
- import {DataType} from './data-type.js';
- import {format} from '@e22m4u/js-format';
- import {PropertyUniqueness} from './property-uniqueness.js';
- import {PropertyValidatorRegistry} from './property-validator/index.js';
- import {PropertyTransformerRegistry} from './property-transformer/index.js';
- import {PropertiesDefinitionValidator} from './properties-definition-validator.js';
- import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
- const S = new PropertiesDefinitionValidator();
- const sandbox = chai.spy.sandbox();
- S.getService(PropertyValidatorRegistry).addValidator('myValidator', () => true);
- S.getService(PropertyTransformerRegistry).addTransformer(
- 'myTransformer',
- () => true,
- );
- describe('PropertiesDefinitionValidator', function () {
- afterEach(function () {
- sandbox.restore();
- });
- describe('validate', function () {
- it('requires a first argument to be a non-empty string', function () {
- const validate = v => () => S.validate(v, {});
- const error = v =>
- format(
- 'The first argument of PropertiesDefinitionValidator.validate ' +
- 'should be a non-empty String, but %s given.',
- v,
- );
- expect(validate('')).to.throw(error('""'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate(false)).to.throw(error('false'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- expect(validate(undefined)).to.throw(error('undefined'));
- expect(validate(null)).to.throw(error('null'));
- validate('model')();
- });
- it('requires a second argument to be an object', function () {
- const validate = v => () => S.validate('model', v);
- const error = v =>
- format(
- 'The provided option "properties" of the model "model" ' +
- 'should be an Object, but %s given.',
- v,
- );
- expect(validate('str')).to.throw(error('"str"'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate(false)).to.throw(error('false'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate(undefined)).to.throw(error('undefined'));
- expect(validate(null)).to.throw(error('null'));
- validate({})();
- });
- it('requires a property name as a non-empty string', function () {
- const validate = v => () => S.validate('model', v);
- const error = v =>
- format(
- 'The property name of the model "model" should be ' +
- 'a non-empty String, but %s given.',
- v,
- );
- expect(validate({['']: {}})).to.throw(error('""'));
- validate({foo: DataType.STRING})();
- });
- it('requires a property definition', function () {
- const validate = v => () => S.validate('model', {foo: v});
- const error = v =>
- format(
- 'The property "foo" of the model "model" should have ' +
- 'a property definition, but %s given.',
- v,
- );
- expect(validate(undefined)).to.throw(error('undefined'));
- expect(validate(null)).to.throw(error('null'));
- validate(DataType.STRING)();
- validate({type: DataType.STRING})();
- });
- it('expects a short property definition to be DataType', function () {
- const validate = v => () => S.validate('model', {foo: v});
- const error = v =>
- format(
- 'In case of a short property definition, the property "foo" ' +
- 'of the model "model" should have one of data types: %l, but %s given.',
- Object.values(DataType),
- v,
- );
- expect(validate('invalid')).to.throw(error('"invalid"'));
- validate(DataType.STRING)();
- });
- it('expects a full property definition to be an object', function () {
- const validate = v => () => S.validate('model', {foo: v});
- const error = v =>
- format(
- 'In case of a full property definition, the property "foo" ' +
- 'of the model "model" should be an Object, but %s given.',
- v,
- );
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate([])).to.throw(error('Array'));
- validate({type: DataType.STRING})();
- });
- it('requires the option "type" to be a DataType', function () {
- const validate = v => () => S.validate('model', {foo: {type: v}});
- const error = v =>
- format(
- 'The property "foo" of the model "model" requires the option "type" ' +
- 'to have one of data types: %l, but %s given.',
- Object.values(DataType),
- v,
- );
- expect(validate('str')).to.throw(error('"str"'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate(false)).to.throw(error('false'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- expect(validate(undefined)).to.throw(error('undefined'));
- expect(validate(null)).to.throw(error('null'));
- validate(DataType.STRING)();
- });
- it('expects the provided option "itemType" to be a DataType', function () {
- const validate = v => {
- const foo = {type: DataType.ARRAY, itemType: v};
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "itemType" of the property "foo" in the model "model" ' +
- 'should have one of data types: %l, but %s given.',
- Object.values(DataType),
- v,
- );
- expect(validate('str')).to.throw(error('"str"'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate(DataType.STRING)();
- });
- it('expects the provided option "itemModel" to be a string', function () {
- const validate = v => {
- const foo = {
- type: DataType.ARRAY,
- itemType: DataType.OBJECT,
- itemModel: v,
- };
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "itemModel" of the property "foo" ' +
- 'in the model "model" should be a String, but %s given.',
- v,
- );
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate('model')();
- });
- it('expects the provided option "model" to be a string', function () {
- const validate = v => {
- const foo = {
- type: DataType.OBJECT,
- model: v,
- };
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "model" of the property "foo" in the model "model" ' +
- 'should be a String, but %s given.',
- v,
- );
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate('model')();
- });
- it('expects the provided option "primaryKey" to be a boolean', function () {
- const validate = v => {
- const foo = {
- type: DataType.STRING,
- primaryKey: v,
- };
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "primaryKey" of the property "foo" in the model "model" ' +
- 'should be a Boolean, but %s given.',
- v,
- );
- expect(validate(10)).to.throw(error('10'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate(true)();
- validate(false)();
- });
- it('expects the provided option "columnName" to be a string', function () {
- const validate = v => {
- const foo = {
- type: DataType.STRING,
- columnName: v,
- };
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "columnName" of the property "foo" in the model "model" ' +
- 'should be a String, but %s given.',
- v,
- );
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate('columnName')();
- });
- it('expects the provided option "columnType" to be a string', function () {
- const validate = v => {
- const foo = {
- type: DataType.STRING,
- columnType: v,
- };
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "columnType" of the property "foo" in the model "model" ' +
- 'should be a String, but %s given.',
- v,
- );
- expect(validate(10)).to.throw(error('10'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate('columnType')();
- });
- it('expects the provided option "required" to be a boolean', function () {
- const validate = v => {
- const foo = {
- type: DataType.STRING,
- required: v,
- };
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "required" of the property "foo" in the model "model" ' +
- 'should be a Boolean, but %s given.',
- v,
- );
- expect(validate('str')).to.throw(error('"str"'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate(true)();
- validate(false)();
- });
- it('expects the required property should not have the option "default" to be provided', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- required: true,
- default: v,
- };
- S.validate('model', {foo});
- };
- const error = format(
- 'The property "foo" of the model "model" is a required property, ' +
- 'so it should not have the option "default" to be provided.',
- );
- expect(validate('str')).to.throw(error);
- expect(validate(10)).to.throw(error);
- expect(validate(true)).to.throw(error);
- expect(validate(false)).to.throw(error);
- expect(validate([])).to.throw(error);
- expect(validate({})).to.throw(error);
- expect(validate(null)).to.throw(error);
- validate(undefined)();
- });
- it('expects the primary key should not have the option "required" to be true', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- primaryKey: true,
- required: v,
- };
- S.validate('model', {foo});
- };
- const error = format(
- 'The property "foo" of the model "model" is a primary key, ' +
- 'so it should not have the option "required" to be provided.',
- );
- expect(validate(true)).to.throw(error);
- validate(false)();
- validate(undefined)();
- });
- it('expects the primary key should not have the option "default" to be provided', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- primaryKey: true,
- default: v,
- };
- S.validate('model', {foo});
- };
- const error = format(
- 'The property "foo" of the model "model" is a primary key, ' +
- 'so it should not have the option "default" to be provided.',
- );
- expect(validate('str')).to.throw(error);
- expect(validate(10)).to.throw(error);
- expect(validate(true)).to.throw(error);
- expect(validate(false)).to.throw(error);
- expect(validate([])).to.throw(error);
- expect(validate({})).to.throw(error);
- expect(validate(null)).to.throw(error);
- validate(undefined)();
- });
- it('expects a non-array property should not have the option "itemType" to be provided', function () {
- const validate = v => () => {
- const foo = {
- type: v,
- itemType: DataType.STRING,
- };
- S.validate('model', {foo});
- };
- const error =
- 'The property "foo" of the model "model" has a non-array type, ' +
- 'so it should not have the option "itemType" to be provided.';
- expect(validate(DataType.ANY)).to.throw(error);
- expect(validate(DataType.STRING)).to.throw(error);
- expect(validate(DataType.NUMBER)).to.throw(error);
- expect(validate(DataType.BOOLEAN)).to.throw(error);
- expect(validate(DataType.OBJECT)).to.throw(error);
- validate(DataType.ARRAY)();
- });
- it('the option "model" requires the "object" property type', function () {
- const validate = v => () => {
- const foo = {
- type: v,
- model: 'model',
- };
- S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The option "model" is not supported for %s property type, ' +
- 'so the property "foo" of the model "model" should not have ' +
- 'the option "model" to be provided.',
- v,
- );
- expect(validate(DataType.ANY)).to.throw(error('Any'));
- expect(validate(DataType.STRING)).to.throw(error('String'));
- expect(validate(DataType.NUMBER)).to.throw(error('Number'));
- expect(validate(DataType.BOOLEAN)).to.throw(error('Boolean'));
- validate(DataType.OBJECT)();
- });
- it('the option "itemModel" requires the "object" item type', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ARRAY,
- itemType: v,
- itemModel: 'model',
- };
- S.validate('model', {foo});
- };
- const errorForNonEmpty = v =>
- format(
- 'The provided option "itemModel" requires the option "itemType" ' +
- 'to be explicitly set to Object, but the property "foo" of ' +
- 'the model "model" has specified item type as %s.',
- v,
- );
- const errorForEmpty = format(
- 'The provided option "itemModel" requires the option "itemType" ' +
- 'to be explicitly set to Object, but the property "foo" of ' +
- 'the model "model" does not have specified item type.',
- );
- expect(validate(DataType.ANY)).to.throw(errorForNonEmpty('Any'));
- expect(validate(DataType.STRING)).to.throw(errorForNonEmpty('String'));
- expect(validate(DataType.NUMBER)).to.throw(errorForNonEmpty('Number'));
- expect(validate(DataType.BOOLEAN)).to.throw(errorForNonEmpty('Boolean'));
- expect(validate(DataType.ARRAY)).to.throw(errorForNonEmpty('Array'));
- expect(validate(undefined)).to.throw(errorForEmpty);
- expect(validate(null)).to.throw(errorForEmpty);
- validate(DataType.OBJECT)();
- });
- it('uses PrimaryKeysDefinitionValidator to validate primary keys', function () {
- const V = S.getService(PrimaryKeysDefinitionValidator);
- sandbox.on(V, 'validate');
- const propDefs = {};
- S.validate('model', propDefs);
- expect(V.validate).to.have.been.called.once;
- expect(V.validate).to.have.been.called.with.exactly('model', propDefs);
- });
- it('the option "validate" should have a non-empty String, an Array of String or an Object', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- validate: v,
- };
- S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "validate" of the property "foo" in the model "model" ' +
- 'should be a non-empty String, an Array of String or an Object, ' +
- 'but %s given.',
- v,
- );
- expect(validate('')).to.throw(error('""'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate(0)).to.throw(error('0'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate(false)).to.throw(error('false'));
- expect(validate(() => undefined)).to.throw(error('Function'));
- validate('myValidator')();
- validate(['myValidator'])();
- validate([])();
- validate({myValidator: true})();
- validate({})();
- validate(null)();
- validate(undefined)();
- });
- it('the option "validate" requires only existing validator names', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- validate: v,
- };
- S.validate('model', {foo});
- };
- const error = v => format('The property validator %s is not found.', v);
- expect(validate('unknown')).to.throw(error('"unknown"'));
- expect(validate({unknown: true})).to.throw(error('"unknown"'));
- expect(validate(['unknown'])).to.throw(error('"unknown"'));
- validate('myValidator')();
- validate(['myValidator'])();
- validate({myValidator: true})();
- });
- it('the option "transform" should have a non-empty String, an Array of String or an Object', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- transform: v,
- };
- S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "transform" of the property "foo" in the model "model" ' +
- 'should be a non-empty String, an Array of String or an Object, ' +
- 'but %s given.',
- v,
- );
- expect(validate('')).to.throw(error('""'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate(0)).to.throw(error('0'));
- expect(validate(true)).to.throw(error('true'));
- expect(validate(false)).to.throw(error('false'));
- expect(validate(() => undefined)).to.throw(error('Function'));
- validate('myTransformer')();
- validate(['myTransformer'])();
- validate([])();
- validate({myTransformer: true})();
- validate({})();
- validate(null)();
- validate(undefined)();
- });
- it('the option "transform" requires only existing transformer names', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- transform: v,
- };
- S.validate('model', {foo});
- };
- const error = v => format('The property transformer %s is not found.', v);
- expect(validate('unknown')).to.throw(error('"unknown"'));
- expect(validate({unknown: true})).to.throw(error('"unknown"'));
- expect(validate(['unknown'])).to.throw(error('"unknown"'));
- validate('myTransformer')();
- validate(['myTransformer'])();
- validate({myTransformer: true})();
- });
- it('expects the provided option "unique" to be a Boolean or the PropertyUniqueness', function () {
- const validate = v => {
- const foo = {
- type: DataType.STRING,
- unique: v,
- };
- return () => S.validate('model', {foo});
- };
- const error = v =>
- format(
- 'The provided option "unique" of the property "foo" in the model "model" ' +
- 'should be a Boolean or one of values: %l, but %s given.',
- Object.values(PropertyUniqueness),
- v,
- );
- expect(validate('str')).to.throw(error('"str"'));
- expect(validate(10)).to.throw(error('10'));
- expect(validate([])).to.throw(error('Array'));
- expect(validate({})).to.throw(error('Object'));
- validate(true)();
- validate(false)();
- validate(PropertyUniqueness.STRICT)();
- validate(PropertyUniqueness.SPARSE)();
- validate(PropertyUniqueness.NON_UNIQUE)();
- });
- it('expects the primary key should not have the option "unique"', function () {
- const validate = v => () => {
- const foo = {
- type: DataType.ANY,
- primaryKey: true,
- unique: v,
- };
- S.validate('model', {foo});
- };
- const error = format(
- 'The property "foo" of the model "model" is a primary key, ' +
- 'so it should not have the option "unique" to be provided.',
- );
- expect(validate(true)).to.throw(error);
- expect(validate(PropertyUniqueness.STRICT)).to.throw(error);
- expect(validate(PropertyUniqueness.SPARSE)).to.throw(error);
- expect(validate(PropertyUniqueness.NON_UNIQUE)).to.throw(error);
- validate(false)();
- validate(undefined)();
- validate(null)();
- });
- });
- });
|