From 9e2610551007f73601f0953853fbe7c5f12bf162 Mon Sep 17 00:00:00 2001 From: Christian Pillsbury Date: Thu, 15 Aug 2019 11:30:07 -0500 Subject: [PATCH] Issue #1061 - Update time and date-time format definitions to support two digit and colon-less variants of timezone offset. Add tests. Update test eslint to include global after function. --- lib/compile/formats.js | 6 +- spec/.eslintrc.yml | 1 + .../1061_alternative_time_offsets.spec.js | 237 ++++++++++++++++++ 3 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 spec/issues/1061_alternative_time_offsets.spec.js diff --git a/lib/compile/formats.js b/lib/compile/formats.js index 5c0fb9ef5..d06792aa4 100644 --- a/lib/compile/formats.js +++ b/lib/compile/formats.js @@ -4,7 +4,7 @@ var util = require('./util'); var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/; var DAYS = [0,31,28,31,30,31,30,31,31,30,31,30,31]; -var TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d:\d\d)?$/i; +var TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i; var HOSTNAME = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*$/i; var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; var URIREF = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i; @@ -33,8 +33,8 @@ formats.fast = { // date: http://tools.ietf.org/html/rfc3339#section-5.6 date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/, // date-time: http://tools.ietf.org/html/rfc3339#section-5.6 - time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i, - 'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i, + time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i, + 'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i, // uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js uri: /^(?:[a-z][a-z0-9+-.]*:)(?:\/?\/)?[^\s]*$/i, 'uri-reference': /^(?:(?:[a-z][a-z0-9+-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i, diff --git a/spec/.eslintrc.yml b/spec/.eslintrc.yml index f9c66d538..543e6eec9 100644 --- a/spec/.eslintrc.yml +++ b/spec/.eslintrc.yml @@ -7,5 +7,6 @@ globals: describe: false it: false before: false + after: false beforeEach: false afterEach: false diff --git a/spec/issues/1061_alternative_time_offsets.spec.js b/spec/issues/1061_alternative_time_offsets.spec.js new file mode 100644 index 000000000..4ff177c56 --- /dev/null +++ b/spec/issues/1061_alternative_time_offsets.spec.js @@ -0,0 +1,237 @@ +"use strict"; + +var Ajv = require("../ajv"); +require("../chai").should(); + +describe("PR #617, full date format validation should understand leap years", function() { + describe("time formats - fast", function() { + var ajv; + var schema; + + before(function() { + ajv = new Ajv({ format: "fast" }); + schema = { format: "time" }; + }); + + after(function() { + ajv = undefined; + schema = undefined; + }); + + it("should treat two digit positive time offsets as valid", function() { + var validTime = "02:31:17+01"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should treat two digit negative time offsets as valid", function() { + var validTime = "02:31:17-01"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should treat four digit positive time offsets without colons as valid", function() { + var validTime = "02:31:17+0130"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should treat four digit negative time offsets without colons as valid", function() { + var validTime = "02:31:17-0130"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should three digit positive time offsets as invalid", function() { + var invalidTime = "02:31:17+013"; + ajv + .validate(schema, invalidTime) + .should.equal(false, "expected " + invalidTime + " to be invalid"); + }); + + it("should treat three digit negative time offsets as invalid", function() { + var invalidTime = "02:31:17-013"; + ajv + .validate(schema, invalidTime) + .should.equal(false, "expected " + invalidTime + " to be invalid"); + }); + }); + + describe("time formats - full", function() { + var ajv; + var schema; + + before(function() { + ajv = new Ajv({ format: "full" }); + schema = { format: "time" }; + }); + + after(function() { + ajv = undefined; + schema = undefined; + }); + + it("should treat two digit positive time offsets as valid", function() { + var validTime = "02:31:17+01"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should treat two digit negative time offsets as valid", function() { + var validTime = "02:31:17-01"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should treat four digit positive time offsets without colons as valid", function() { + var validTime = "02:31:17+0130"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should treat four digit negative time offsets without colons as valid", function() { + var validTime = "02:31:17-0130"; + ajv + .validate(schema, validTime) + .should.equal(true, "expected " + validTime + " to be valid"); + }); + + it("should three digit positive time offsets as invalid", function() { + var invalidTime = "02:31:17+013"; + ajv + .validate(schema, invalidTime) + .should.equal(false, "expected " + invalidTime + " to be invalid"); + }); + + it("should treat three digit negative time offsets as invalid", function() { + var invalidTime = "02:31:17-013"; + ajv + .validate(schema, invalidTime) + .should.equal(false, "expected " + invalidTime + " to be invalid"); + }); + }); + + describe("date-time formats - fast", function() { + var ajv; + var schema; + + before(function() { + ajv = new Ajv({ format: "fast" }); + schema = { format: "date-time" }; + }); + + after(function() { + ajv = undefined; + schema = undefined; + }); + + it("should treat two digit positive time offsets as valid", function() { + var validDateTime = "2016-01-31T02:31:17+01"; + ajv + .validate(schema, validDateTime) + .should.equal(true, "expected " + validDateTime + " to be valid"); + }); + + it("should treat two digit negative time offsets as valid", function() { + var validDateTime = "2016-01-31T02:31:17-01"; + ajv + .validate(schema, validDateTime) + .should.equal(true, "expected " + validDateTime + " to be valid"); + }); + + it("should treat four digit positive time offsets without colons as valid", function() { + var validDateTime = "2016-01-31T02:31:17+0130"; + ajv + .validate(schema, validDateTime) + .should.equal(true, "expected " + validDateTime + " to be valid"); + }); + + it("should treat four digit negative time offsets without colons as valid", function() { + var validDateTime = "2016-01-31T02:31:17-0130"; + ajv + .validate(schema, validDateTime) + .should.equal(true, "expected " + validDateTime + " to be valid"); + }); + + it("should three digit positive time offsets as invalid", function() { + var invalidDateTime = "2016-01-31T02:31:17+013"; + ajv + .validate(schema, invalidDateTime) + .should.equal(false, "expected " + invalidDateTime + " to be invalid"); + }); + + it("should treat three digit negative time offsets as invalid", function() { + var invalidDateTime = "2016-01-31T02:31:17-013"; + ajv + .validate(schema, invalidDateTime) + .should.equal(false, "expected " + invalidDateTime + " to be invalid"); + }); + }); + + describe("date-time formats - full", function() { + var ajv; + var schema; + + before(function() { + ajv = new Ajv({ format: "full" }); + schema = { format: "date-time" }; + }); + + after(function() { + ajv = undefined; + schema = undefined; + }); + + it("should treat two digit positive time offsets as valid", function() { + var validDateTime = "2016-01-31T02:31:17+01"; + ajv + .validate(schema, validDateTime) + .should.equal(true, "expected " + validDateTime + " to be valid"); + }); + + it("should treat two digit negative time offsets as valid", function() { + var validDateTime = "2016-01-31T02:31:17-01"; + ajv + .validate(schema, validDateTime) + .should.equal(true, "expected " + validDateTime + " to be valid"); + }); + + it("should treat four digit positive time offsets without colons as valid", function() { + var validDateTime = "2016-01-31T02:31:17+0130"; + ajv + .validate(schema, validDateTime) + .should.equal( + true, + "2016-01-31Texpected " + validDateTime + " to be valid" + ); + }); + + it("should treat four digit negative time offsets without colons as valid", function() { + var validDateTime = "2016-01-31T02:31:17-0130"; + ajv + .validate(schema, validDateTime) + .should.equal(true, "expected " + validDateTime + " to be valid"); + }); + + it("should three digit positive time offsets as invalid", function() { + var invalidDateTime = "2016-01-31T02:31:17+013"; + ajv + .validate(schema, invalidDateTime) + .should.equal(false, "expected " + invalidDateTime + " to be invalid"); + }); + + it("should treat three digit negative time offsets as invalid", function() { + var invalidDateTime = "2016-01-31T02:31:17-013"; + ajv + .validate(schema, invalidDateTime) + .should.equal(false, "expected " + invalidDateTime + " to be invalid"); + }); + }); +});