synctos
Version:
The Syncmaker. A tool to build comprehensive sync functions for Couchbase Sync Gateway.
361 lines (351 loc) • 27.3 kB
JavaScript
const { expect } = require('chai');
const docDefinitionsLoader = require('../loading/document-definitions-loader');
const validator = require('./document-definitions-validator');
describe('Document definitions validator:', () => {
it('performs validation on the sample document definitions file', () => {
const filePath = 'samples/sample-sync-doc-definitions.js';
const sampleDocDefinitions = docDefinitionsLoader.load(filePath);
const results = validator.validate(sampleDocDefinitions, filePath);
expect(results.length).to.equal(0);
});
it('performs validation on a document definitions object', () => {
const fakeDocDefinitions = {
myDoc1: {
documentIdRegexPattern: { }, // Must be a RegExp object
allowUnknownProperties: 1, // Must be a boolean
immutable: true,
cannotDelete: true, // Must not be defined if "immutable" is also defined
attachmentConstraints: (a, b) => b, // "allowAttachments" must also be defined
accessAssignments: [
{ // Must include either a "roles" or "users" property
channels: [ ] // Must not be empty
},
{ // Must include a "channels" property
type: 'channel',
roles: [ ], // Must not be empty
},
{
type: 'role',
roles: [ 1 ], // Must only contain strings
users: [ ], // Must not be empty
channels: [ 'foo' ] // The "channels" property is not supported for the "role" type of assignment
},
{
type: 'invalid-type' // Must be either "role", "channel" or null
}
],
expiry: -25637, // Must be no less than zero
customActions: {
onTypeIdentificationSucceeded: (a, b, c, extraParam) => extraParam, // Too many parameters
onAuthorizationSucceeded: 5, // Must be a function
onExpiryAssignmentSucceeded: (a, b, c) => c,
invalidEvent: (a, b, c) => c // Unsupported event type
}
}
};
const results = validator.validate(fakeDocDefinitions);
expect(results).to.have.members(
[
'myDoc1: "value" must contain at least one of [channels, authorizedRoles, authorizedUsers]',
'myDoc1.typeFilter: "typeFilter" is required',
'myDoc1.propertyValidators: "propertyValidators" is required',
'myDoc1.documentIdRegexPattern: \"documentIdRegexPattern\" must be an instance of \"RegExp\"',
'myDoc1.allowUnknownProperties: \"allowUnknownProperties\" must be a boolean',
'myDoc1.immutable: \"immutable\" conflict with forbidden peer \"cannotDelete\"',
'myDoc1.allowAttachments: \"allowAttachments\" is required',
'myDoc1.accessAssignments.0: \"value\" must contain at least one of [roles, users]',
'myDoc1.accessAssignments.0.channels: \"channels\" must contain at least 1 items',
'myDoc1.accessAssignments.1.channels: \"channels\" is required',
'myDoc1.accessAssignments.1.roles: \"roles\" must contain at least 1 items',
'myDoc1.accessAssignments.2.roles.0: \"0\" must be a string',
'myDoc1.accessAssignments.2.users: \"users\" must contain at least 1 items',
'myDoc1.accessAssignments.2.channels: \"channels\" is not allowed',
'myDoc1.accessAssignments.3.type: \"type\" must be one of [channel, role, null]',
'myDoc1.expiry: \"expiry\" must be larger than or equal to 0',
'myDoc1.customActions.onTypeIdentificationSucceeded: \"onTypeIdentificationSucceeded\" must have an arity lesser or equal to 3',
'myDoc1.customActions.onAuthorizationSucceeded: \"onAuthorizationSucceeded\" must be a Function',
'myDoc1.customActions.invalidEvent: \"invalidEvent\" is not allowed'
]);
});
it('performs validation on a document definitions function', () => {
const fakeDocDefinitions = () => {
return {
myDoc1: {
typeFilter: () => { },
channels: { }, // Must have at least one permission type
authorizedRoles: { }, // Must have at least one permission type
authorizedUsers: { }, // Must have at least one permission type
documentIdRegexPattern: (a, extraParam) => extraParam, // Too many parameters
immutable: true,
cannotReplace: false, // Must not be defined if "immutable" is also defined
allowAttachments: false, // Must be true since "attachmentConstraints" is defined
attachmentConstraints: {
maximumAttachmentCount: 0, // Must be at least 1
maximumIndividualSize: 20971521, // Must be no greater than 20971520 (the max Sync Gateway attachment size)
maximumTotalSize: 20971520, // Must be greater or equal to "maximumIndividualSize"
supportedExtensions: (doc, oldDoc, extraParam) => [ extraParam ], // Has too many params
supportedContentTypes: [ ], // Must have at least one element
filenameRegexPattern: { foo: 'bar' } // Must be a RegExp
},
accessAssignments: (a, b, extraParam) => extraParam, // Too many parameters
customActions: { }, // Must have at least one property
propertyValidators: {
conditionalTypeProperty: {
type: 'conditional',
immutableWhenSetStrict: true,
mustNotBeNull: false, // "mustNotBeNull" is deprecated
minimumValue: -15, // Unsupported constraint for this validation type
validationCandidates: [
{
condition: (a, b, c, d, extra) => extra, // Too many parameters and must have a "validator" property
foobar: 'baz' // Unsupported property
},
{
condition: true, // Must be a function
validator: {
type: 'float',
maximumLength: 3, // Unsupported constraint for this validation type
mustEqual: (a, b, c, d) => d
}
},
{
condition: () => true,
validator: {
type: 'object',
allowUnknownProperties: 0 // Must be a boolean
}
}
]
},
timeProperty: {
type: 'time',
immutable: 1, // Must be a boolean
minimumValue: '15', // Must have at least hour and minute components
maximumValue: '23:49:52.1234', // Must not have more than 3 fractional digits
mustEqual: 'foobar' // Must be a valid time string
},
timezoneProperty: {
type: 'timezone',
minimumValueExclusive: '-15', // Must include minute component
maximumValueExclusive: '19:00', // Must have a positive or negative sign
mustEqual: 'barfoo' // Must be a valid timezone string
},
_invalidName: { // Sync Gateway does not allow top-level property names to start with underscore
type: 'string'
},
nestedObject: {
type: 'object',
unrecognizedConstraint: true, // Invalid property constraint
propertyValidators: {
_validName: {
type: 'boolean',
skipValidationWhenValueUnchanged: 1, // Must be a boolean
skipValidationWhenValueUnchangedStrict: true // Must not be defined in conjunction with "skipValidationWhenValueUnchanged"
},
dateProperty: {
type: 'date',
required: true,
immutable: true,
immutableWhenSet: false, // Must not be defined in conjunction with "immutable"
maximumValue: '2018-01-31T17:31:27.283-08:00', // Should not include time and time zone components
mustEqualStrict: new Date('1578-11-30'), // Must be a date string for equality
customValidation: (a, b, c, d, extraParam) => extraParam // Too many parameters
},
enumProperty: {
type: 'enum',
predefinedValues: [
'foo',
'bar',
3,
1.9 // Must include only strings and integers
],
mustEqual: true, // Must be an integer or string
mustEqualStrict: 3 // Must not be defined in conjunction with "mustEqual"
},
attachmentReferenceProperty: {
type: 'attachmentReference',
regexPattern: '^abc$' // Must be a RegExp object
},
hashtableProperty: {
type: 'hashtable',
minimumSize: 2,
maximumSize: 1, // Must not be less than "minimumSize"
hashtableKeysValidator: {
regexPattern: '^[a-z]+$' // Must actually be either a literal regex or a RegExp object
},
hashtableValuesValidator: {
type: 'datetime',
minimumValue: 'Mon, 25 Dec 1995 13:30:00 +0430', // Must be an ISO 8601 date string
maximumValueExclusive: new Date(2018, 0, 31, 17, 31, 27, 283), // Must not be defined in conjunction with "mustEqual"
mustEqual: new Date('2018-01-31T17:31:27.283-08:00') // Must be a date string for equality
}
},
arrayProperty: {
type: 'array',
minimumLength: 3.5, // Must be an integer
maximumLength: 3.5, // Must be an integer
arrayElementsValidator: {
type: 'object',
allowUnknownProperties: true,
required: (doc, oldDoc, value, oldValue) => oldValue === true,
propertyValidators: {
stringProperty: {
type: 'string',
mustEqual: 'FooBar', // Must not be defined in conjunction with "mustEqualIgnoreCase"
mustEqualIgnoreCase: null, // Must not be null or defined with "mustEqual"
mustBeTrimmed: 0, // Must be a boolean
regexPattern: /^[a-z]+$/,
minimumLength: () => 9,
maximumLength: -1 // Must be at least 0
},
booleanProperty: {
type: 'boolean',
mustEqual: 'true' // Must be a boolean
},
validIntegerProperty: {
type: 'integer',
minimumValue: 5,
maximumValueExclusive: 6
},
invalidIntegerProperty: {
type: 'integer',
required: true,
mustNotBeMissing: true, // "mustNotBeMissing" is deprecated
minimumValueExclusive: 1,
maximumValue: 1, // Must be greater than "minimumValueExclusive"
maximumValueExclusive: 1 // Must be greater than "minimumValueExclusive"
},
validFloatProperty: {
type: 'float',
minimumValueExclusive: 1,
maximumValue: 1.0001
},
invalidFloatProperty: {
type: 'float',
minimumValue: 31.9,
maximumValue: 31.89998, // Must be at least "minimumValue"
maximumValueExclusive: 31.9 // Must be greater than "minimumValue"
},
uuidProperty: {
type: 'uuid',
minimumValue: '4050b662-4383-4d2E-8771-54d380d11C41',
maximumValue: '1234' // Not a valid UUID
},
noTypeProperty: { // The "type" property is required
required: true
},
invalidMustEqualConstraintProperty: {
type: 'object',
mustEqual: [ ] // Must be an object
},
emptyPropertyValidatorsProperty: {
type: 'object',
mustEqual: (a, b, c, d) => d,
propertyValidators: { } // Must specify at least one property validator
},
anyProperty: {
type: 'any',
minimumValue: 32, // Not supported by the "any" type
mustNotBeEmpty: false, // Not supported by the "any" type
regexPattern: /^foo$/ // Not supported by the "any" type
}
}
}
},
unrecognizedTypeProperty: {
type: 'foobar' // Not a supported validation constraint type
}
}
}
},
expiry: '20180415T1357-0700' // Must be a valid ISO 8601 date string
}
};
};
const results = validator.validate(fakeDocDefinitions);
expect(results).to.have.members(
[
'myDoc1.channels: \"channels\" must have at least 1 children',
'myDoc1.authorizedRoles: \"authorizedRoles\" must have at least 1 children',
'myDoc1.authorizedUsers: \"authorizedUsers\" must have at least 1 children',
'myDoc1.documentIdRegexPattern: \"documentIdRegexPattern\" must have an arity lesser or equal to 1',
'myDoc1.immutable: \"immutable\" conflict with forbidden peer \"cannotReplace\"',
'myDoc1.allowAttachments: \"allowAttachments\" must be one of [true]',
'myDoc1.attachmentConstraints.maximumAttachmentCount: \"maximumAttachmentCount\" must be larger than or equal to 1',
'myDoc1.attachmentConstraints.maximumIndividualSize: \"maximumIndividualSize\" must be less than or equal to 20971520',
'myDoc1.attachmentConstraints.maximumTotalSize: \"maximumTotalSize\" must be larger than or equal to 20971521',
'myDoc1.attachmentConstraints.supportedExtensions: "supportedExtensions" must have an arity lesser or equal to 2',
'myDoc1.attachmentConstraints.supportedContentTypes: \"supportedContentTypes\" must contain at least 1 items',
'myDoc1.attachmentConstraints.filenameRegexPattern: \"filenameRegexPattern\" must be an instance of \"RegExp\"',
'myDoc1.accessAssignments: \"accessAssignments\" must have an arity lesser or equal to 2',
'myDoc1.customActions: \"customActions\" must have at least 1 children',
'myDoc1.propertyValidators.conditionalTypeProperty.mustNotBeNull: \"mustNotBeNull\" is deprecated; use "required" instead',
'myDoc1.propertyValidators.conditionalTypeProperty.minimumValue: \"minimumValue\" is not allowed',
'myDoc1.propertyValidators.conditionalTypeProperty.validationCandidates.0.condition: \"condition\" must have an arity lesser or equal to 4',
'myDoc1.propertyValidators.conditionalTypeProperty.validationCandidates.0.foobar: \"foobar\" is not allowed',
'myDoc1.propertyValidators.conditionalTypeProperty.validationCandidates.0.validator: \"validator\" is required',
'myDoc1.propertyValidators.conditionalTypeProperty.validationCandidates.1.condition: \"condition\" must be a Function',
'myDoc1.propertyValidators.conditionalTypeProperty.validationCandidates.1.validator.maximumLength: \"maximumLength\" is not allowed',
'myDoc1.propertyValidators.conditionalTypeProperty.validationCandidates.2.validator.allowUnknownProperties: \"allowUnknownProperties\" must be a boolean',
'myDoc1.propertyValidators.timeProperty.immutable: \"immutable\" must be a boolean',
'myDoc1.propertyValidators.timeProperty.minimumValue: \"minimumValue\" with value \"15\" fails to match the required pattern: /^((([01]\\d|2[0-3])(:[0-5]\\d)(:[0-5]\\d(\\.\\d{1,3})?)?)|(24:00(:00(\\.0{1,3})?)?))$/',
'myDoc1.propertyValidators.timeProperty.maximumValue: \"maximumValue\" with value \"23:49:52.1234\" fails to match the required pattern: /^((([01]\\d|2[0-3])(:[0-5]\\d)(:[0-5]\\d(\\.\\d{1,3})?)?)|(24:00(:00(\\.0{1,3})?)?))$/',
'myDoc1.propertyValidators.timeProperty.mustEqual: \"mustEqual\" with value \"foobar\" fails to match the required pattern: /^((([01]\\d|2[0-3])(:[0-5]\\d)(:[0-5]\\d(\\.\\d{1,3})?)?)|(24:00(:00(\\.0{1,3})?)?))$/',
'myDoc1.propertyValidators.timeProperty.minimumValue: \"minimumValue\" conflict with forbidden peer \"mustEqual\"',
'myDoc1.propertyValidators.timeProperty.maximumValue: \"maximumValue\" conflict with forbidden peer \"mustEqual\"',
'myDoc1.propertyValidators.timezoneProperty.minimumValueExclusive: \"minimumValueExclusive\" with value \"-15\" fails to match the required pattern: /^(Z|([+-])([01]\\d|2[0-3]):([0-5]\\d))$/',
'myDoc1.propertyValidators.timezoneProperty.maximumValueExclusive: \"maximumValueExclusive\" with value \"19:00\" fails to match the required pattern: /^(Z|([+-])([01]\\d|2[0-3]):([0-5]\\d))$/',
'myDoc1.propertyValidators.timezoneProperty.mustEqual: \"mustEqual\" with value \"barfoo\" fails to match the required pattern: /^(Z|([+-])([01]\\d|2[0-3]):([0-5]\\d))$/',
'myDoc1.propertyValidators.timezoneProperty.minimumValueExclusive: \"minimumValueExclusive\" conflict with forbidden peer \"mustEqual\"',
'myDoc1.propertyValidators.timezoneProperty.maximumValueExclusive: \"maximumValueExclusive\" conflict with forbidden peer \"mustEqual\"',
'myDoc1.propertyValidators._invalidName: "_invalidName" is not allowed',
'myDoc1.propertyValidators.nestedObject.unrecognizedConstraint: "unrecognizedConstraint" is not allowed',
'myDoc1.propertyValidators.nestedObject.propertyValidators._validName.skipValidationWhenValueUnchanged: \"skipValidationWhenValueUnchanged\" must be a boolean',
'myDoc1.propertyValidators.nestedObject.propertyValidators._validName.skipValidationWhenValueUnchanged: \"skipValidationWhenValueUnchanged\" conflict with forbidden peer \"skipValidationWhenValueUnchangedStrict\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.dateProperty.immutableWhenSet: \"immutableWhenSet\" conflict with forbidden peer \"immutable\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.dateProperty.immutable: \"immutable\" conflict with forbidden peer \"immutableWhenSet\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.dateProperty.maximumValue: "maximumValue" with value "2018-01-31T17:31:27.283-08:00" fails to match the required pattern: /^([+-]\\d{6}|\\d{4})(-(0[1-9]|1[0-2])(-(0[1-9]|[12]\\d|3[01]))?)?$/',
'myDoc1.propertyValidators.nestedObject.propertyValidators.dateProperty.maximumValue: \"maximumValue\" conflict with forbidden peer \"mustEqualStrict\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.dateProperty.mustEqualStrict: \"mustEqualStrict\" must be a string',
'myDoc1.propertyValidators.nestedObject.propertyValidators.dateProperty.customValidation: \"customValidation\" must have an arity lesser or equal to 4',
'myDoc1.propertyValidators.nestedObject.propertyValidators.enumProperty.predefinedValues.3: \"predefinedValues\" at position 3 does not match any of the allowed types',
'myDoc1.propertyValidators.nestedObject.propertyValidators.enumProperty.mustEqual: \"mustEqual\" conflict with forbidden peer \"mustEqualStrict\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.enumProperty.mustEqualStrict: \"mustEqualStrict\" conflict with forbidden peer \"mustEqual\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.enumProperty.mustEqual: \"mustEqual\" must be a string',
'myDoc1.propertyValidators.nestedObject.propertyValidators.enumProperty.mustEqual: \"mustEqual\" must be a number',
'myDoc1.propertyValidators.nestedObject.propertyValidators.attachmentReferenceProperty.regexPattern: \"regexPattern\" must be an object',
'myDoc1.propertyValidators.nestedObject.propertyValidators.hashtableProperty.maximumSize: \"maximumSize\" must be larger than or equal to 2',
'myDoc1.propertyValidators.nestedObject.propertyValidators.hashtableProperty.hashtableKeysValidator.regexPattern: "regexPattern" must be an object',
'myDoc1.propertyValidators.nestedObject.propertyValidators.hashtableProperty.hashtableValuesValidator.minimumValue: \"minimumValue\" with value \"Mon, 25 Dec 1995 13:30:00 +0430\" fails to match the required pattern: /^([+-]\\d{6}|\\d{4})(-(0[1-9]|1[0-2])(-(0[1-9]|[12]\\d|3[01]))?)?(T((([01]\\d|2[0-3])(:[0-5]\\d)(:[0-5]\\d(\\.\\d{1,3})?)?)|(24:00(:00(\\.0{1,3})?)?))(Z|([+-])([01]\\d|2[0-3]):([0-5]\\d))?)?$/',
'myDoc1.propertyValidators.nestedObject.propertyValidators.hashtableProperty.hashtableValuesValidator.minimumValue: \"minimumValue\" conflict with forbidden peer \"mustEqual\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.hashtableProperty.hashtableValuesValidator.maximumValueExclusive: "maximumValueExclusive" conflict with forbidden peer "mustEqual"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.hashtableProperty.hashtableValuesValidator.mustEqual: \"mustEqual\" must be a string',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.minimumLength: \"minimumLength\" must be an integer',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.maximumLength: \"maximumLength\" must be an integer',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.stringProperty.mustEqual: \"mustEqual\" conflict with forbidden peer \"mustEqualIgnoreCase\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.stringProperty.mustEqualIgnoreCase: \"mustEqualIgnoreCase\" conflict with forbidden peer \"mustEqual\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.stringProperty.mustEqualIgnoreCase: \"mustEqualIgnoreCase\" must be a string',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.stringProperty.mustBeTrimmed: \"mustBeTrimmed\" must be a boolean',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.stringProperty.maximumLength: \"maximumLength\" must be larger than or equal to 0',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.booleanProperty.mustEqual: \"mustEqual\" must be a boolean',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidIntegerProperty.mustNotBeMissing: \"mustNotBeMissing\" is deprecated; use "required" instead',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidIntegerProperty.maximumValue: \"maximumValue\" must be greater than 1',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidIntegerProperty.maximumValue: \"maximumValue\" conflict with forbidden peer \"maximumValueExclusive\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidIntegerProperty.maximumValueExclusive: \"maximumValueExclusive\" must be greater than 1',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidIntegerProperty.maximumValueExclusive: \"maximumValueExclusive\" conflict with forbidden peer \"maximumValue\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidFloatProperty.maximumValueExclusive: \"maximumValueExclusive\" must be greater than 31.9',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidFloatProperty.maximumValue: \"maximumValue\" must be larger than or equal to 31.9',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidFloatProperty.maximumValue: \"maximumValue\" conflict with forbidden peer \"maximumValueExclusive\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidFloatProperty.maximumValueExclusive: \"maximumValueExclusive\" conflict with forbidden peer \"maximumValue\"',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.uuidProperty.maximumValue: "maximumValue" must be a valid GUID',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.invalidMustEqualConstraintProperty.mustEqual: \"mustEqual\" must be an object',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.emptyPropertyValidatorsProperty.propertyValidators: \"propertyValidators\" must have at least 1 children',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.noTypeProperty.type: "type" is required',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.anyProperty.minimumValue: \"minimumValue\" is not allowed',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.anyProperty.mustNotBeEmpty: \"mustNotBeEmpty\" is not allowed',
'myDoc1.propertyValidators.nestedObject.propertyValidators.arrayProperty.arrayElementsValidator.propertyValidators.anyProperty.regexPattern: \"regexPattern\" is not allowed',
'myDoc1.propertyValidators.nestedObject.propertyValidators.unrecognizedTypeProperty.type: \"type\" must be one of [any, array, attachmentReference, boolean, conditional, date, datetime, enum, float, hashtable, integer, object, string, time, timezone, uuid]',
'myDoc1.expiry: \"expiry\" with value \"20180415T1357-0700\" fails to match the required pattern: /^\\d{4}-(((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\\d|30))|(02-(0[1-9]|[12]\\d)))T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(Z|[+-]([01]\\d|2[0-3]):[0-5]\\d)$/',
]);
});
});