jenkins-bot has submitted this change and it was merged. Change subject: [time.js] added time.Time.validate and use it in time.Time constructor ......................................................................
[time.js] added time.Time.validate and use it in time.Time constructor time.Time.validate checks whether a given plain object representing a time makes sense. If not, an error will be thrown. Change-Id: I1431c9f9bdeff711713a4f5c56ae8b1c63bcb533 --- M DataValues/DataValues.resources.php M DataValues/DataValues.tests.qunit.php M DataValues/resources/time.js/src/time.Time.js A DataValues/resources/time.js/src/time.Time.validate.js A DataValues/resources/time.js/tests/time.Time.validate.tests.js 5 files changed, 238 insertions(+), 2 deletions(-) Approvals: Henning Snater: Looks good to me, approved jenkins-bot: Verified diff --git a/DataValues/DataValues.resources.php b/DataValues/DataValues.resources.php index 9174296..b4038df 100644 --- a/DataValues/DataValues.resources.php +++ b/DataValues/DataValues.resources.php @@ -90,6 +90,7 @@ 'scripts' => array( 'time.js/src/time.js', 'time.js/src/time.Time.js', + 'time.js/src/time.Time.validate.js', 'time.js/src/time.Time.parse.js', ), 'dependencies' => array( diff --git a/DataValues/DataValues.tests.qunit.php b/DataValues/DataValues.tests.qunit.php index 758fe2a..c574dd4 100644 --- a/DataValues/DataValues.tests.qunit.php +++ b/DataValues/DataValues.tests.qunit.php @@ -85,6 +85,7 @@ 'resources/time.js/tests/time.Time.knowsPrecision.tests.js', 'resources/time.js/tests/time.Time.minPrecision.tests.js', 'resources/time.js/tests/time.Time.maxPrecision.tests.js', + 'resources/time.js/tests/time.Time.validate.tests.js', ), 'dependencies' => array( 'time.js', diff --git a/DataValues/resources/time.js/src/time.Time.js b/DataValues/resources/time.js/src/time.Time.js index f6839d8..2fcfed6 100644 --- a/DataValues/resources/time.js/src/time.Time.js +++ b/DataValues/resources/time.js/src/time.Time.js @@ -25,6 +25,8 @@ * precision. * {string} calendarname: Default calendar name overruling the automatically detected * calendar. + * + * @throws {Error} If given time Definition is an Object not representing a valid time. */ var Time = function Time( timeDefinition, options ) { var result; @@ -35,9 +37,10 @@ }, options ); if( typeof timeDefinition === 'string' ) { - result = time.Time.parse( timeDefinition ); + result = Time.parse( timeDefinition ); } else { - result = $.extend( {}, timeDefinition ); + result = $.extend( {}, timeDefinition ); // copy object + Time.validate( result ); } if( result === null ) { result = {}; diff --git a/DataValues/resources/time.js/src/time.Time.validate.js b/DataValues/resources/time.js/src/time.Time.validate.js new file mode 100644 index 0000000..79d1a2d --- /dev/null +++ b/DataValues/resources/time.js/src/time.Time.validate.js @@ -0,0 +1,79 @@ +/** + * time.Time.validate for validating structures passed to the time.Time constructor. + * + * @since 0.1 + * @file + * @ingroup Time.js + * @licence GNU GPL v2+ + * + * @author Daniel Werner < daniel.wer...@wikimedia.de > + */ +time.Time.validate = ( function( Time ) { + 'use strict'; + + /** + * Makes sure a given time structure is valid. If not, an Error will be thrown. + * + * @param {Object} definition + * @throws {Error} + */ + return function validateTimeDefinition( definition ) { + validateFieldTypes( definition, { + day: 'number', + month: 'number', + year: 'number', + calendarname: 'string', + precision: 'number' + } ); + + if( definition.year === undefined || isNaN( definition.year ) ) { + throw new Error( '"year" has to be a number' ); + } + + if( definition.month > 12 || definition.month < 1 ) { + throw new Error( '"month" must not be lower than 1 (January) or higher than 12 ' + + '(December). "' + definition.month + '" is not a valid month number.' ); + } + + if( definition.day < 1 ) { + throw new Error( '"day" must not be lower than 1' ); + } + // TODO: Add check for last day of the month once we have one validator per calendar model. + + // TODO: remove the following check once we have one validator per calendar model: + if( definition.calendarname !== Time.CALENDAR.GREGORIAN + && definition.calendarname !== Time.CALENDAR.JULIAN + ) { + throw new Error( '"calendarname" is "' + definition.calendarname + '" but has to be "' + + Time.CALENDAR.GREGORIAN + '" or "' + Time.CALENDAR.JULIAN + '"' ); + } + + if( !Time.knowsPrecision( definition.precision ) ) { + throw new Error( 'Unknown precision "' + definition.precision + '" given in "precision"' ); + } + }; + + /** + * Checks a definition for certain fields. If the field is available, an error will be thrown + * in case the field is not of the specified type. + * + * @param {{key: string, type: string}} fieldTypes + * @param {Object} definition + */ + function validateFieldTypes( fieldTypes, definition ) { + var field, value, requiredType; + + for( field in definition ) { + value = fieldTypes[ field ]; + requiredType = definition[ field ]; + + if( !requiredType ) { + throw new Error( 'Unknown field "' + field + '" found in structure' ); + } + if( value !== undefined && typeof value !== requiredType ) { + throw new Error( 'Field "' + field + '" has to be of type ' + requiredType ); + } + } + } + +}( time.Time ) ); diff --git a/DataValues/resources/time.js/tests/time.Time.validate.tests.js b/DataValues/resources/time.js/tests/time.Time.validate.tests.js new file mode 100644 index 0000000..97c5240 --- /dev/null +++ b/DataValues/resources/time.js/tests/time.Time.validate.tests.js @@ -0,0 +1,152 @@ +/** + * @since 0.1 + * @file + * @ingroup Time.js + * + * @licence GNU GPL v2+ + * @author Daniel Werner + */ +( function( QUnit, $, Time ) { + 'use strict'; + + var PRECISION = Time.PRECISION, + G = Time.CALENDAR.GREGORIAN, + J = Time.CALENDAR.JULIAN; + + QUnit.module( 'time.js: time.Time.validate()' ); + + var validDefinitions = [ + { + calendarname: G, + year: -44, + precision: PRECISION.YEAR + }, { + calendarname: J, + year: 1492, + month: 10, + day: 12, + precision: PRECISION.DAY + }, { + calendarname: G, + month: 3, + year: -44, + precision: PRECISION.MONTH + }, { + calendarname: J, + year: 1616, + month: 4, + day: 23, + precision: PRECISION.DAY + }, { + calendarname: G, + year: 1616, + month: 4, + day: 22, + precision: PRECISION.DAY + }, { + calendarname: G, + year: 2001, + month: 1, + day: 1, + precision: PRECISION.DAY + }, { + calendarname: G, + year: 1989, + month: 11, + day: 20, + precision: PRECISION.DAY + } + ]; + + QUnit.test( 'validating valid time definitions', function( assert ) { + $.each( validDefinitions, function( i, timeDefinition ) { + var valid = true; + try { + Time.validate( timeDefinition ); // throws an error if failure + } catch( e ) { + valid = false; + } + + assert.ok( + valid, + 'valid definition ' + i + ' has been accepted by validate()' + ); + } ); + } ); + + var validDefinition = { + calendarname: J, + year: 1492, + month: 10, + day: 12, + precision: PRECISION.DAY + }; + + function newInvalidTestDefinition( reason, change ) { + return { + reason: reason, + definition: $.extend( {}, validDefinition, change ) + }; + } + + var invalidDefinitions = [ + { + reason: 'no object given', + definition: null + }, + newInvalidTestDefinition( + 'invalid precision (string)', + { precision: 'foo' } + ), + newInvalidTestDefinition( + 'invalid numeric precision', + { precision: Time.maxPrecision() + 1 } + ), + newInvalidTestDefinition( + 'invalid year (string)', + { year: 'foo' } + ), + newInvalidTestDefinition( + 'invalid year NaN', + { year: Number.NaN } + ), + newInvalidTestDefinition( + 'month above 12', + { month: 13 } + ), + newInvalidTestDefinition( + 'month below 1', + { month: -1 } + ), + newInvalidTestDefinition( + 'month below 1', + { month: 0 } + ), + newInvalidTestDefinition( + 'day below 1', + { month: 0 } + ), + newInvalidTestDefinition( + 'unknown calendar name', + { calendarname: 'foo' } + ) + ]; + + QUnit.test( 'validating invalid time definitions', function( assert ) { + Time.validate( newInvalidTestDefinition( '', { year: 1234 } ).definition ); + assert.ok( + true, + 'Checked for test helper. Valid definition used as base is actually valid.' + ); + + $.each( invalidDefinitions, function( i, timeTestDefinition ) { + assert.throws( + function() { + Time.validate( timeTestDefinition.definition ); + }, + 'Validation of time object ' + i + ' failed because of ' + timeTestDefinition.reason + ); + } ); + } ); + +}( QUnit, jQuery, time.Time ) ); -- To view, visit https://gerrit.wikimedia.org/r/63990 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I1431c9f9bdeff711713a4f5c56ae8b1c63bcb533 Gerrit-PatchSet: 6 Gerrit-Project: mediawiki/extensions/DataValues Gerrit-Branch: master Gerrit-Owner: Daniel Werner <daniel.wer...@wikimedia.de> Gerrit-Reviewer: Henning Snater <henning.sna...@wikimedia.de> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits