]> git.ipfire.org Git - thirdparty/moment.git/commitdiff
tests and a working isDSTShifted
authorIsaac Cambron <isaac@isaaccambron.com>
Fri, 27 Sep 2013 20:49:37 +0000 (16:49 -0400)
committerIsaac Cambron <isaac@isaaccambron.com>
Fri, 27 Sep 2013 20:49:37 +0000 (16:49 -0400)
moment.js
test/moment.parsing_flags.js [new file with mode: 0644]
test/moment/create.js
test/moment/invalid.js
test/moment/is_valid.js

index de4f4456636550f765a12c316c30449b49400c4d..107fbc06108d96595d1b15ab0a39db1f5a1584a2 100644 (file)
--- a/moment.js
+++ b/moment.js
             empty : false,
             unusedTokens : [],
             trailingInput : '',
+            skippedInput : [],
             overflowMonthOk : false,
             dstShifted : false,
             overflow : -2,
-            charsLeftOver: 0
+            charsLeftOver : 0,
+            nullInput : false,
+            invalidMonth : null,
+            userInvalidated : false
         };
     }
 
             m._isValid = !isNaN(m._d.getTime()) &&
                 m._pf.overflow < 0 &&
                 !m._pf.empty &&
-                !m._pf.invalidMonth;
+                !m._pf.invalidMonth &&
+                !m._pf.nullInput &&
+                !m._pf.userInvalidated;
 
             if (m._strict) {
                 m._isValid = m._isValid &&
         // This array is used to make a Date, either with `new Date` or `Date.UTC`
         var lang = getLangDefinition(config._l),
             string = '' + config._i,
-            i, parsedInput, tokens, regex, token,
+            i, parsedInput, tokens, token, skipped,
             stringLength = string.length,
             totalParsedInputLength = 0;
 
 
         for (i = 0; i < tokens.length; i++) {
             token = tokens[i];
-            regex = getParseRegexForToken(token, config);
-            if (config._strict) {
-                regex = new RegExp("^" + regex.source, regex.ignoreCase ? "i" : "");
-            }
-            parsedInput = (regex.exec(string) || [])[0];
+            parsedInput = (getParseRegexForToken(token, config).exec(string) || [])[0];
             if (parsedInput) {
+                skipped = string.substr(0, string.indexOf(parsedInput));
+                if (skipped.length > 0) {
+                    config._pf.skippedInput.push(skipped);
+                }
                 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
                 totalParsedInputLength += parsedInput.length;
             }
                 if (parsedInput) {
                     config._pf.empty = false;
                 }
+                else {
+                    config._pf.unusedTokens.push(token);
+                }
                 addTimeToArrayFromToken(token, parsedInput, config);
             }
+            else if (config._strict && !parsedInput) {
+                config._pf.unusedTokens.push(token);
+            }
         }
 
         // add remaining unparsed input length to the string
             initializeParsingFlags(config);
         }
 
-        if (input === null ||
-            (typeof input === 'string' &&
-             input.replace(/^\s+|\s+$/g, '') === '')) {
-            return moment.invalid();
+        if (input === null) {
+            return moment.invalid({nullInput: true});
         }
 
         if (typeof input === 'string') {
         return normalizeUnits(units);
     };
 
-    moment.invalid = function () {
+    moment.invalid = function (flags) {
         var m = moment.utc(NaN);
-        m._isValid = false;
+        if (flags != null) {
+            extend(m._pf, flags);
+        }
+        else {
+            m._pf.userInvalidated = true;
+        }
         return m;
     };
 
 
             if (this._a) {
                 //this is best-effort. What if it's a valid overflow AND DST-shifted?
-                return !this._pf.overflowMonthOk && !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray());
+                return this.isValid() && !this._pf.overflowMonthOk && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
             }
 
             return false;
diff --git a/test/moment.parsing_flags.js b/test/moment.parsing_flags.js
new file mode 100644 (file)
index 0000000..1b716c7
--- /dev/null
@@ -0,0 +1,181 @@
+var moment = require('../../moment'),
+    flags = function () {
+        return moment.apply(null, arguments).parsingFlags();
+    };
+
+exports.parsing_flags = {
+
+    'overflow with array' : function (test) {
+
+        //months
+        test.equal(flags([2010, 0]).overflow, -1, 'month 0 valid');
+        test.equal(flags([2010, 1]).overflow, -1, 'month 1 valid');
+        test.equal(flags([2010, -1]).overflow, 1, 'month -1 invalid');
+        test.equal(flags([2100, 12]).overflow, 1, 'month 12 invalid');
+
+        //days
+        test.equal(flags([2010, 1, 16]).overflow, -1, 'date valid');
+        test.equal(flags([2010, 1, -1]).overflow, 2, 'date -1 invalid');
+        test.equal(flags([2010, 1, 0]).overflow, 2, 'date 0 invalid');
+        test.equal(flags([2010, 1, 32]).overflow, 2, 'date 32 invalid');
+        test.equal(flags([2012, 1, 29]).overflow, -1, 'date leap year valid');
+        test.equal(flags([2010, 1, 29]).overflow, 2, 'date leap year invalid');
+
+        //hours
+        test.equal(flags([2010, 1, 1, 8]).overflow, -1, 'hour valid');
+        test.equal(flags([2010, 1, 1, 0]).overflow, -1, 'hour 0 valid');
+        test.equal(flags([2010, 1, 1, -1]).overflow, 3, 'hour -1 invalid');
+        test.equal(flags([2010, 1, 1, 24]).overflow, 3, 'hour 24 invalid');
+
+        //minutes
+        test.equal(flags([2010, 1, 1, 8, 15]).overflow, -1, 'minute valid');
+        test.equal(flags([2010, 1, 1, 8, 0]).overflow, -1, 'minute 0 valid');
+        test.equal(flags([2010, 1, 1, 8, -1]).overflow, 4, 'minute -1 invalid');
+        test.equal(flags([2010, 1, 1, 8, 60]).overflow, 4, 'minute 60 invalid');
+
+        //seconds
+        test.equal(flags([2010, 1, 1, 8, 15, 12]).overflow, -1, 'second valid');
+        test.equal(flags([2010, 1, 1, 8, 15, 0]).overflow, -1, 'second 0 valid');
+        test.equal(flags([2010, 1, 1, 8, 15, -1]).overflow, 5, 'second -1 invalid');
+        test.equal(flags([2010, 1, 1, 8, 15, 60]).overflow, 5, 'second 60 invalid');
+
+        //milliseconds
+        test.equal(flags([2010, 1, 1, 8, 15, 12, 345]).overflow, -1, 'millisecond valid');
+        test.equal(flags([2010, 1, 1, 8, 15, 12, 0]).overflow, -1, 'millisecond 0 valid');
+        test.equal(flags([2010, 1, 1, 8, 15, 12, -1]).overflow, 6, 'millisecond -1 invalid');
+        test.equal(flags([2010, 1, 1, 8, 15, 12, 1000]).overflow, 6, 'millisecond 1000 invalid');
+
+        test.done();
+    },
+
+    'overflow without format' : function (test) {
+
+        //months
+        test.equal(flags('2001-01', 'YYYY-MM').overflow, -1, 'month 1 valid');
+        test.equal(flags('2001-12', 'YYYY-MM').overflow, -1, 'month 12 valid');
+        test.equal(flags('2001-13', 'YYYY-MM').overflow, 1, 'month 13 invalid');
+
+        //days
+        test.equal(flags('2010-01-16', 'YYYY-MM-DD').overflow, -1, 'date 16 valid');
+        test.equal(flags('2010-01-0',  'YYYY-MM-DD').overflow, 2, 'date 0 invalid');
+        test.equal(flags('2010-01-32', 'YYYY-MM-DD').overflow, 2, 'date 32 invalid');
+        test.equal(flags('2012-02-29', 'YYYY-MM-DD').overflow, -1, 'date leap year valid');
+        test.equal(flags('2010-02-29', 'YYYY-MM-DD').overflow, 2, 'date leap year invalid');
+
+        //days of the year
+        test.equal(flags('2010 300', 'YYYY DDDD').overflow, -1, 'day 300 of year valid');
+        test.equal(flags('2010 365', 'YYYY DDDD').overflow, -1, 'day 365 of year valid');
+        test.equal(flags('2010 366', 'YYYY DDDD').overflow, 2, 'day 366 of year invalid');
+        test.equal(flags('2012 364', 'YYYY DDDD').overflow, -1, 'day 364 of leap year valid');
+        test.equal(flags('2012 365', 'YYYY DDDD').overflow, 2, 'day 365 of leap year invalid');
+
+        //hours
+        test.equal(flags('08', 'HH').overflow, -1, 'hour valid');
+        test.equal(flags('00', 'HH').overflow, -1, 'hour 0 valid');
+        test.equal(flags('24', 'HH').overflow, 3, 'hour 24 invalid');
+
+        //minutes
+        test.equal(flags('08:15', 'HH:mm').overflow, -1, 'minute valid');
+        test.equal(flags('08:00', 'HH:mm').overflow, -1, 'minute 0 valid');
+        test.equal(flags('08:60', 'HH:mm').overflow, 4, 'minute 60 invalid');
+
+        //seconds
+        test.equal(flags('08:15:12', 'HH:mm:ss').overflow, -1, 'second valid');
+        test.equal(flags('08:15:00', 'HH:mm:ss').overflow, -1, 'second 0 valid');
+        test.equal(flags('08:15:60', 'HH:mm:ss').overflow, 5, 'second 60 invalid');
+
+        //milliseconds
+        test.equal(flags('08:15:12:345', 'HH:mm:ss:SSSS').overflow, -1, 'millisecond valid');
+        test.equal(flags('08:15:12:000', 'HH:mm:ss:SSSS').overflow, -1, 'millisecond 0 valid');
+
+        //this is OK because we don't match the last digit, so it's 100 ms
+        test.equal(flags('08:15:12:1000', 'HH:mm:ss:SSSS').overflow, -1, 'millisecond 1000 actually valid');
+
+        test.done();
+    },
+
+    'extra tokens' : function (test) {
+
+        test.deepEqual(flags('1982-05-25', 'YYYY-MM-DD').unusedTokens, [], 'nothing extra');
+        test.deepEqual(flags('1982-05', 'YYYY-MM-DD').unusedTokens, ['DD'], 'extra formatting token');
+        test.deepEqual(flags('1982', 'YYYY-MM-DD').unusedTokens, ['MM', 'DD'], 'multiple extra formatting tokens');
+        test.deepEqual(flags('1982-05', 'YYYY-MM-').unusedTokens, [], 'extra non-formatting token');
+        test.deepEqual(flags('1982-05-', 'YYYY-MM-DD').unusedTokens, ['DD'], 'non-extra non-formatting token');
+        test.deepEqual(flags('1982 05 1982', 'YYYY-MM-DD').unusedTokens, [], 'different non-formatting token');
+
+        test.done();
+    },
+
+    'extra tokens strict' : function (test) {
+
+        test.deepEqual(flags('1982-05-25', 'YYYY-MM-DD', true).unusedTokens, [], 'nothing extra');
+        test.deepEqual(flags('1982-05', 'YYYY-MM-DD', true).unusedTokens, ['-', 'DD'], 'extra formatting token');
+        test.deepEqual(flags('1982', 'YYYY-MM-DD', true).unusedTokens, ['-', 'MM', '-', 'DD'], 'multiple extra formatting tokens');
+        test.deepEqual(flags('1982-05', 'YYYY-MM-', true).unusedTokens, ['-'], 'extra non-formatting token');
+        test.deepEqual(flags('1982-05-', 'YYYY-MM-DD', true).unusedTokens, ['DD'], 'non-extra non-formatting token');
+        test.deepEqual(flags('1982 05 1982', 'YYYY-MM-DD', true).unusedTokens, ['-', '-'], 'different non-formatting token');
+
+        test.done();
+    },
+
+    'trailing output' : function (test) {
+        test.equal(flags('1982-05-25', 'YYYY-MM-DD').trailingInput, '', 'normal input');
+        test.equal(flags('1982-05-25 this is more stuff', 'YYYY-MM-DD').trailingInput, ' this is more stuff', 'trailing nonsense');
+        test.equal(flags('1982-05-25 09:30', 'YYYY-MM-DD').trailingInput, ' 09:30', 'trailing legit-looking input');
+        test.equal(flags('1982-05-25 some junk', 'YYYY-MM-DD [some junk]').trailingInput, '', 'junk that actually gets matched');
+
+        test.done();
+    },
+
+    'skipped input' : function (test) {
+        test.deepEqual(flags('1982-05-25', 'YYYY-MM-DD').skippedInput, [], 'normal input');
+        test.deepEqual(flags('stuff at beginning 1982-05-25', 'YYYY-MM-DD').skippedInput, ['stuff at beginning '], 'leading junk');
+        test.deepEqual(flags('1982 junk 05 more junk25', 'YYYY-MM-DD').skippedInput, [' junk ', ' more junk'], 'interstitial junk');
+
+        test.done();
+    },
+
+    'skipped input strict' : function (test) {
+        test.deepEqual(flags('1982-05-25', 'YYYY-MM-DD').skippedInput, [], 'normal input');
+        test.deepEqual(flags('stuff at beginning 1982-05-25', 'YYYY-MM-DD').skippedInput, ['stuff at beginning '], 'leading junk');
+        test.deepEqual(flags('1982 junk 05 more junk25', 'YYYY-MM-DD').skippedInput, [' junk ', ' more junk'], 'interstitial junk');
+
+        test.done();
+    },
+
+    'chars left over' : function (test) {
+        test.equal(flags('1982-05-25', 'YYYY-MM-DD').charsLeftOver, 0, 'normal input');
+        test.equal(flags('1982-05-25 this is more stuff', 'YYYY-MM-DD').charsLeftOver, ' this is more stuff'.length, 'trailing nonsense');
+        test.equal(flags('1982-05-25 09:30', 'YYYY-MM-DD').charsLeftOver, ' 09:30'.length, 'trailing legit-looking input');
+        test.equal(flags('stuff at beginning 1982-05-25', 'YYYY-MM-DD').charsLeftOver, 'stuff at beginning '.length, 'leading junk');
+        test.equal(flags('1982 junk 05 more junk25', 'YYYY-MM-DD').charsLeftOver, [' junk ', ' more junk'].join('').length, 'interstitial junk');
+        test.equal(flags('stuff at beginning 1982 junk 05 more junk25', 'YYYY-MM-DD').charsLeftOver, ['stuff at beginning ', ' junk ', ' more junk'].join('').length, 'leading and interstitial junk');
+
+        test.done();
+    },
+
+    'empty' : function (test) {
+        test.equal(flags('1982-05-25', 'YYYY-MM-DD').empty, false, 'normal input');
+        test.equal(flags('nothing here', 'YYYY-MM-DD').empty, true, 'pure garbage');
+        test.equal(flags('junk but has the number 2000 in it', 'YYYY-MM-DD').empty, false, 'only mostly garbage');
+        test.equal(flags('', 'YYYY-MM-DD').empty, true, 'empty string');
+        test.equal(flags('', 'YYYY-MM-DD').empty, true, 'blank string');
+
+        test.done();
+    },
+
+    'null' : function (test) {
+        test.equal(flags('1982-05-25', 'YYYY-MM-DD').nullInput, false, 'normal input');
+        test.equal(flags(null).nullInput, true, 'just null');
+        test.equal(flags(null, 'YYYY-MM-DD').nullInput, true, 'null with format');
+
+        test.done();
+    },
+
+    'invalid month' : function (test) {
+        test.equal(flags('1982 May', 'YYYY MMMM').invalidMonth, null, 'normal input');
+        test.equal(flags('1982 Laser', 'YYYY MMMM').invalidMonth, 'Laser', 'bad month name');
+
+        test.done();
+    }
+};
index 34b5ce5f096edf77f2e8bf3e4660ba92dfc9ea69..03adba3424275cc5ff3968589b32414e376a0971 100644 (file)
@@ -306,7 +306,7 @@ exports.create = {
     },
 
     "string with array of formats" : function (test) {
-        test.expect(16);
+        test.expect(19);
 
         test.equal(moment('11-02-1999', ['MM-DD-YYYY', 'DD-MM-YYYY']).format('MM DD YYYY'), '11 02 1999', 'switching month and day');
         test.equal(moment('02-11-1999', ['MM/DD/YYYY', 'YYYY MM DD', 'MM-DD-YYYY']).format('MM DD YYYY'), '02 11 1999', 'year last');
@@ -323,6 +323,10 @@ exports.create = {
         test.equal(moment('02-01-2000', ['DD/MM/YYYY', 'MM/DD/YYYY']).format('MM DD YYYY'), '01 02 2000', 'either can be a month, day first format');
 
         test.equal(moment('11-02-10', ['MM/DD/YY', 'YY MM DD', 'DD-MM-YY']).format('MM DD YYYY'), '02 11 2010', 'all unparsed substrings have influence on format penalty');
+        test.equal(moment('11-02-10', ['MM-DD-YY HH:mm', 'YY MM DD']).format('MM DD YYYY'), '02 10 2011', 'prefer formats without extra tokens');
+        test.equal(moment('11-02-10 junk', ['MM-DD-YY', 'YY.MM.DD junk']).format('MM DD YYYY'), '02 10 2011', 'prefer formats that dont result in extra characters');
+        test.equal(moment('11-22-10', ['YY-MM-DD', 'YY-DD-MM']).format('MM DD YYYY'), '10 22 2011', 'prefer valid results');
+
         test.equal(moment('11-02-10', ['MM.DD.YY', 'DD-MM-YY']).format('MM DD YYYY'), '02 11 2010', 'escape RegExp special characters on comparing');
 
         test.equal(moment('13-14-98', ['DD MM YY', 'DD MM YYYY'])._f, 'DD MM YY', 'use two digit year');
@@ -509,11 +513,12 @@ exports.create = {
     },
 
     "strict parsing" : function (test) {
-        test.expect(10);
+        test.expect(11);
         test.equal(moment("2012-05", "YYYY-MM", true).format("YYYY-MM"), "2012-05", "parse correct string");
         test.equal(moment(" 2012-05", "YYYY-MM", true).isValid(), false, "fail on extra whitespace");
         test.equal(moment("foo 2012-05", "[foo] YYYY-MM", true).format('YYYY-MM'), "2012-05", "handle fixed text");
         test.equal(moment("2012 05", "YYYY-MM", true).isValid(), false, "fail on different separator");
+        test.equal(moment("2012 05", "YYYY MM DD", true).isValid(), false, "fail on too many tokens");
 
         test.equal(moment("05 30 2010", ["DD MM YYYY", "MM DD YYYY"], true).format("MM DD YYYY"), "05 30 2010", "array with bad date");
         test.equal(moment("05 30 2010", ["", "MM DD YYYY"], true).format("MM DD YYYY"), "05 30 2010", "array with invalid format");
index be764c37fae867ee872bbceb9b5d0d83beae763a..494a4890d27f145e26a9dd4d6f6b6fee13ffc8b7 100644 (file)
@@ -4,6 +4,25 @@ exports.invalid = {
     "invalid" : function (test) {
         var m = moment.invalid();
         test.equals(m.isValid(), false);
+        test.equals(m.parsingFlags().userInvalidated, true);
+        test.ok(isNaN(m.valueOf()));
+        test.done();
+    },
+
+    "invalid with existing flag" : function (test) {
+        var m = moment.invalid({invalidMonth : 'whatchamacallit'});
+        test.equals(m.isValid(), false);
+        test.equals(m.parsingFlags().userInvalidated, false);
+        test.equals(m.parsingFlags().invalidMonth, 'whatchamacallit');
+        test.ok(isNaN(m.valueOf()));
+        test.done();
+    },
+
+    "invalid with custom flag" : function (test) {
+        var m = moment.invalid({tooBusyWith : 'reiculating splines'});
+        test.equals(m.isValid(), false);
+        test.equals(m.parsingFlags().userInvalidated, false);
+        test.equals(m.parsingFlags().tooBusyWith, 'reiculating splines');
         test.ok(isNaN(m.valueOf()));
         test.done();
     }
index ead45fd6b29f7f358c33944b518e032ddac5d0fa..99fc2c134f10860fc8f6ee4800ef299f256f24d3 100644 (file)
@@ -2,15 +2,9 @@ var moment = require("../../moment");
 
 exports.is_valid = {
     "array bad month" : function (test) {
-        var underflow = moment([2010, -1]),
-            overflow = moment([2100, 12]);
-
-        test.expect(4);
-        test.equal(underflow.isValid(), false, 'month -1 invalid');
-        test.equal(underflow.parsingFlags().overflow, 1, 'month -1 overflow');
-
-        test.equal(overflow.isValid(), false, 'month 12 invalid');
-        test.equal(overflow.parsingFlags().overflow, 1, 'month 12 invalid');
+        test.expect(2);
+        test.equal(moment([2010, -1]).isValid(), false, 'month -1 invalid');
+        test.equal(moment([2100, 12]).isValid(), false, 'month 12 invalid');
 
         test.done();
     },
@@ -35,12 +29,11 @@ exports.is_valid = {
         ],
         i, m;
 
-        test.expect(tests.length * 2);
+        test.expect(tests.length);
 
         for (i in tests) {
             m = tests[i];
             test.equal(m.isValid(), false);
-            test.equal(m.parsingFlags().overflow, 2);
         }
 
         test.done();
@@ -234,5 +227,26 @@ exports.is_valid = {
 
         test.equal(moment(" ", "X").isValid(), false, 'string space');
         test.done();
-    }
+    },
+
+    "empty" : function (test) {
+        test.equal(moment(null).isValid(), false, 'null');
+        test.equal(moment('').isValid(), false, 'empty string');
+        test.equal(moment(' ').isValid(), false, 'empty when trimmed');
+
+        test.equal(moment(null, 'YYYY').isValid(), false, 'format + null');
+        test.equal(moment('', 'YYYY').isValid(), false, 'format + empty string');
+        test.equal(moment(' ', 'YYYY').isValid(), false, 'format + empty when trimmed');
+        test.done();
+    },
+
+    "oddball permissiveness" : function (test) {
+        //https://github.com/moment/moment/issues/1128
+        test.ok(moment("2010-10-3199", ["MM/DD/YYYY", "MM-DD-YYYY", "YYYY-MM-DD"]).isValid());
+
+        //https://github.com/moment/moment/issues/1122
+        test.ok(moment("3:25", ["h:mma", "hh:mma", "H:mm", "HH:mm"]).isValid());
+
+        test.done()
+    },
 };