parseValidISO.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. /// <reference path="../UnitTestFramework/UnitTestFramework.js" />
  6. if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
  7. this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  8. }
  9. initializeGenerateDateStrings();
  10. var yearDigits = 0, monthDigits = 0, dayDigits = 0, hourMinuteDigits = 0, secondDigits = 0, millisecondDigits = 0;
  11. var tests = [{
  12. name: "Test if valid ISO date strings are parsed correctly",
  13. body: function () {
  14. for (yearDigits = 4; yearDigits <= 6; yearDigits += 2) {
  15. dayDigits = monthDigits = 0;
  16. runGenerateTestWithValidTime();
  17. monthDigits = 2;
  18. runGenerateTestWithValidTime();
  19. dayDigits = 2;
  20. runGenerateTestWithValidTime();
  21. }
  22. }
  23. }];
  24. function runGenerateTestWithValidTime() {
  25. millisecondDigits = secondDigits = hourMinuteDigits = 0;
  26. runGenerateTest();
  27. hourMinuteDigits = 2;
  28. runGenerateTest();
  29. secondDigits = 2;
  30. runGenerateTest();
  31. millisecondDigits = 3;
  32. runGenerateTest();
  33. }
  34. testRunner.run(tests, { verbose: WScript.Arguments[0] != "summary" });
  35. // Test-specific helpers
  36. function runTest(testString) {
  37. var dateObj = new Date(testString);
  38. var timeValue1;
  39. try {
  40. timeValue1 = dateObj.getTime();
  41. } catch (ex) {
  42. assert.fail("Unable to parse Date \"" + testString + "\". Error is " + ex.message);
  43. }
  44. assert.isFalse(isNaN(timeValue1), "Unable to parse Date \"" + testString + "\"");
  45. var ISOString = dateObj.toISOString();
  46. console.log(ISOString);
  47. var timeValue2;
  48. try {
  49. timeValue2 = new Date(ISOString).getTime();
  50. } catch (ex) {
  51. assert.fail("Unable to parse Date \"" + ISOString + "\". Error is " + ex.message);
  52. }
  53. assert.areEqual(timeValue1, timeValue2, "Date \"" + testString + "\" is not parsed correctly.");
  54. }
  55. function runGenerateTest() {
  56. var s =
  57. generateDateStrings(
  58. yearDigits,
  59. monthDigits,
  60. dayDigits,
  61. hourMinuteDigits,
  62. hourMinuteDigits,
  63. secondDigits,
  64. millisecondDigits);
  65. for (var i = 0; i < s.length; ++i)
  66. runTest(s[i]);
  67. }
  68. var signs, zones;
  69. function initializeGenerateDateStrings() {
  70. signs = ["+", "-"];
  71. zones = ["", "Z"];
  72. var zoneDigitCombinations = ["00", "01", "10"];
  73. for (var i = 0; i < zoneDigitCombinations.length; ++i)
  74. for (var j = 0; j < zoneDigitCombinations.length; ++j)
  75. for (var k = 0; k < signs.length; ++k)
  76. zones.push(signs[k] + zoneDigitCombinations[i] + ":" + zoneDigitCombinations[j]);
  77. }
  78. // Generates date strings in the following format:
  79. // date format: "[+|-]YYYYYY[-MM[-DD]]"
  80. // separator: "T| "
  81. // time format: "HH:mm[:ss[.sss]]"
  82. // time zone: "Z|(+|-)HH:mm"
  83. // - The separator is required only if both the date and time portions are included in the string.
  84. // - Zero-padding is optional
  85. // - Positive sign (+) is optional when the year is nonnegative
  86. // - Negative sign (-) is optional when the year is zero
  87. // - Time zone is optional
  88. //
  89. // The function will return an array of strings to test against, based on the parameters.
  90. function generateDateStrings(
  91. yearDigits, // number of digits to include for the year (0-6), 0 - exclude the year (monthDigits must also be 0)
  92. monthDigits, // number of digits to include for the month (0-2), 0 - exclude the month (dayDigits must also be 0)
  93. dayDigits, // number of digits to include for the day (0-2), 0 - exclude the day
  94. hourDigits, // number of digits to include for the hour (0-2), 0 - exclude the hour (minuteDigits must also be 0)
  95. minuteDigits, // number of digits to include for the minute (0-2), 0 - exclude the minute (hourDigits and secondDigits must also be 0)
  96. secondDigits, // number of digits to include for the second (0-2), 0 - exclude the second (millisecondDigits must also be 0)
  97. millisecondDigits) // number of digits to include for the millisecond (0-3), 0 - exclude the millisecond
  98. {
  99. if (yearDigits === 0 && monthDigits !== 0 ||
  100. monthDigits === 0 && dayDigits !== 0 ||
  101. hourDigits === 0 && minuteDigits !== 0 ||
  102. minuteDigits === 0 && (hourDigits !== 0 || secondDigits !== 0) ||
  103. secondDigits === 0 && millisecondDigits !== 0 ||
  104. yearDigits === 0 && (hourDigits === 0 || minuteDigits === 0))
  105. return [];
  106. var s = [""];
  107. if (yearDigits !== 0) {
  108. appendDigits(s, yearDigits, true);
  109. if (monthDigits !== 0) {
  110. append(s, ["-"]);
  111. appendDigits(s, monthDigits, false);
  112. if (dayDigits !== 0) {
  113. append(s, ["-"]);
  114. appendDigits(s, dayDigits, false);
  115. }
  116. }
  117. }
  118. if (hourDigits !== 0 && minuteDigits !== 0) {
  119. append(s, ["T"]);
  120. appendDigits(s, hourDigits, true);
  121. append(s, [":"]);
  122. appendDigits(s, minuteDigits, true);
  123. if (secondDigits !== 0) {
  124. append(s, [":"]);
  125. appendDigits(s, secondDigits, true);
  126. if (millisecondDigits !== 0) {
  127. append(s, ["."]);
  128. appendDigits(s, millisecondDigits, true);
  129. }
  130. }
  131. }
  132. if (yearDigits !== 0 && hourDigits !== 0 && minuteDigits !== 0)
  133. s = applyToEach(s, zones, function (str, zone) { return str + zone; });
  134. if (yearDigits === 6) {
  135. s =
  136. applyToEach(
  137. s,
  138. signs,
  139. function (str, sign) {
  140. if (sign === "-" && str.length >= 6 && str.substring(0, 6) === "000000")
  141. return undefined; // "-000000" is not allowed
  142. return sign + str;
  143. });
  144. }
  145. return s;
  146. }
  147. // Appends interesting combinations of n digits to the string array
  148. function appendDigits(a, n, includeZero) {
  149. var d = [];
  150. switch (n) {
  151. case 0:
  152. break;
  153. case 1:
  154. if (includeZero)
  155. d.push("0");
  156. d.push("1");
  157. append(a, d);
  158. break;
  159. case 3:
  160. case 6:
  161. if (n === 3)
  162. d.push("010");
  163. else
  164. d.push("010010");
  165. default:
  166. var z = zeroes(n - 1);
  167. if (includeZero)
  168. d.push(z + "0");
  169. d.push(z + "1");
  170. d.push("1" + z);
  171. append(a, d);
  172. break;
  173. }
  174. }
  175. // Returns a string of n zeroes
  176. function zeroes(n) {
  177. var s = "";
  178. while (n-- > 0)
  179. s += "0";
  180. return s;
  181. }
  182. // Appends patterns to the string array. The array is extended to acommodate the number of patterns, and the patterns are
  183. // repeated to acommodate the length of the array.
  184. function append(a, p) {
  185. extend(a, p.length);
  186. for (var i = 0; i < a.length; ++i)
  187. a[i] += p[i % p.length];
  188. }
  189. // Applies the function 'f' to each combination of elements in 'a' and 'p'. 'f' will receive the element of 'a' on which it
  190. // should apply the pattern from 'p' and it should return the modified string. The string returned by 'f' will be pushed onto a
  191. // new array, which will be returned.
  192. function applyToEach(a, p, f) {
  193. var a2 = [];
  194. for (var i = 0; i < a.length; ++i) {
  195. for (var j = 0; j < p.length; ++j) {
  196. var transformed = f(a[i], p[j]);
  197. if (transformed !== undefined)
  198. a2.push(transformed);
  199. }
  200. }
  201. return a2;
  202. }
  203. // Extends an array to have length n, by copying the last element as necessary
  204. function extend(a, n) {
  205. var originalLength = a.length;
  206. for (var i = originalLength; i < n; ++i)
  207. a.push(a[originalLength - 1]);
  208. }