1package goja 2 3import ( 4 "testing" 5 "time" 6) 7 8const TESTLIB = ` 9function $ERROR(message) { 10 throw new Error(message); 11} 12 13function Test262Error() { 14} 15 16function assert(mustBeTrue, message) { 17 if (mustBeTrue === true) { 18 return; 19 } 20 21 if (message === undefined) { 22 message = 'Expected true but got ' + String(mustBeTrue); 23 } 24 $ERROR(message); 25} 26 27assert._isSameValue = function (a, b) { 28 if (a === b) { 29 // Handle +/-0 vs. -/+0 30 return a !== 0 || 1 / a === 1 / b; 31 } 32 33 // Handle NaN vs. NaN 34 return a !== a && b !== b; 35}; 36 37assert.sameValue = function (actual, expected, message) { 38 if (assert._isSameValue(actual, expected)) { 39 return; 40 } 41 42 if (message === undefined) { 43 message = ''; 44 } else { 45 message += ' '; 46 } 47 48 message += 'Expected SameValue(«' + String(actual) + '», «' + String(expected) + '») to be true'; 49 50 $ERROR(message); 51}; 52 53assert.throws = function (expectedErrorConstructor, func, message) { 54 if (typeof func !== "function") { 55 $ERROR('assert.throws requires two arguments: the error constructor ' + 56 'and a function to run'); 57 return; 58 } 59 if (message === undefined) { 60 message = ''; 61 } else { 62 message += ' '; 63 } 64 65 try { 66 func(); 67 } catch (thrown) { 68 if (typeof thrown !== 'object' || thrown === null) { 69 message += 'Thrown value was not an object!'; 70 $ERROR(message); 71 } else if (thrown.constructor !== expectedErrorConstructor) { 72 message += 'Expected a ' + expectedErrorConstructor.name + ' but got a ' + thrown.constructor.name; 73 $ERROR(message); 74 } 75 return; 76 } 77 78 message += 'Expected a ' + expectedErrorConstructor.name + ' to be thrown but no exception was thrown at all'; 79 $ERROR(message); 80}; 81 82function compareArray(a, b) { 83 if (b.length !== a.length) { 84 return false; 85 } 86 87 for (var i = 0; i < a.length; i++) { 88 if (b[i] !== a[i]) { 89 return false; 90 } 91 } 92 return true; 93} 94` 95 96const TESTLIBX = TESTLIB + 97 `function looksNative(fn) { 98 return /native code/.test(Function.prototype.toString.call(fn)); 99 } 100 101 function deepEqual(a, b) { 102 if (typeof a === "object") { 103 if (typeof b === "object") { 104 if (a === b) { 105 return true; 106 } 107 if (Reflect.getPrototypeOf(a) !== Reflect.getPrototypeOf(b)) { 108 return false; 109 } 110 var keysA = Object.keys(a); 111 var keysB = Object.keys(b); 112 if (keysA.length !== keysB.length) { 113 return false; 114 } 115 if (!compareArray(keysA.sort(), keysB.sort())) { 116 return false; 117 } 118 for (var i = 0; i < keysA.length; i++) { 119 var key = keysA[i]; 120 if (!deepEqual(a[key], b[key])) { 121 return false; 122 } 123 } 124 return true; 125 } else { 126 return false; 127 } 128 } 129 return assert._isSameValue(a, b); 130 } 131` 132 133func TestDateUTC(t *testing.T) { 134 const SCRIPT = ` 135 assert.sameValue(Date.UTC(1970, 0), 0, '1970, 0'); 136 assert.sameValue(Date.UTC(2016, 0), 1451606400000, '2016, 0'); 137 assert.sameValue(Date.UTC(2016, 6), 1467331200000, '2016, 6'); 138 139 assert.sameValue(Date.UTC(2016, 6, 1), 1467331200000, '2016, 6, 1'); 140 assert.sameValue(Date.UTC(2016, 6, 5), 1467676800000, '2016, 6, 5'); 141 142 assert.sameValue(Date.UTC(2016, 6, 5, 0), 1467676800000, '2016, 6, 5, 0'); 143 assert.sameValue(Date.UTC(2016, 6, 5, 15), 1467730800000, '2016, 6, 5, 15'); 144 145 assert.sameValue( 146 Date.UTC(2016, 6, 5, 15, 0), 1467730800000, '2016, 6, 5, 15, 0' 147 ); 148 assert.sameValue( 149 Date.UTC(2016, 6, 5, 15, 34), 1467732840000, '2016, 6, 5, 15, 34' 150 ); 151 152 assert.sameValue( 153 Date.UTC(2016, 6, 5, 15, 34, 0), 1467732840000, '2016, 6, 5, 15, 34, 0' 154 ); 155 assert.sameValue( 156 Date.UTC(2016, 6, 5, 15, 34, 45), 1467732885000, '2016, 6, 5, 15, 34, 45' 157 ); 158 159 ` 160 161 testScript1(TESTLIB+SCRIPT, _undefined, t) 162} 163 164func TestNewDate(t *testing.T) { 165 const SCRIPT = ` 166 var d1 = new Date("2016-09-01T12:34:56Z"); 167 d1.getUTCHours() === 12; 168 169 ` 170 testScript1(SCRIPT, valueTrue, t) 171} 172 173func TestNewDate0(t *testing.T) { 174 const SCRIPT = ` 175 (new Date(0)).toUTCString(); 176 177 ` 178 testScript1(SCRIPT, asciiString("Thu, 01 Jan 1970 00:00:00 GMT"), t) 179} 180 181func TestSetHour(t *testing.T) { 182 l := time.Local 183 defer func() { 184 time.Local = l 185 }() 186 var err error 187 time.Local, err = time.LoadLocation("America/New_York") 188 if err != nil { 189 t.Fatal(err) 190 } 191 192 const SCRIPT = ` 193 var d = new Date(2016, 8, 1, 12, 23, 45) 194 assert.sameValue(d.getHours(), 12); 195 assert.sameValue(d.getUTCHours(), 16); 196 197 d.setHours(13); 198 assert.sameValue(d.getHours(), 13); 199 assert.sameValue(d.getMinutes(), 23); 200 assert.sameValue(d.getSeconds(), 45); 201 202 d.setUTCHours(13); 203 assert.sameValue(d.getHours(), 9); 204 assert.sameValue(d.getMinutes(), 23); 205 assert.sameValue(d.getSeconds(), 45); 206 207 ` 208 testScript1(TESTLIB+SCRIPT, _undefined, t) 209 210} 211 212func TestSetMinute(t *testing.T) { 213 l := time.Local 214 defer func() { 215 time.Local = l 216 }() 217 time.Local = time.FixedZone("Asia/Delhi", 5*60*60+30*60) 218 219 const SCRIPT = ` 220 var d = new Date(2016, 8, 1, 12, 23, 45) 221 assert.sameValue(d.getHours(), 12); 222 assert.sameValue(d.getUTCHours(), 6); 223 assert.sameValue(d.getMinutes(), 23); 224 assert.sameValue(d.getUTCMinutes(), 53); 225 226 d.setMinutes(55); 227 assert.sameValue(d.getMinutes(), 55); 228 assert.sameValue(d.getSeconds(), 45); 229 230 d.setUTCMinutes(52); 231 assert.sameValue(d.getMinutes(), 22); 232 assert.sameValue(d.getHours(), 13); 233 234 ` 235 testScript1(TESTLIB+SCRIPT, _undefined, t) 236 237} 238 239func TestTimezoneOffset(t *testing.T) { 240 const SCRIPT = ` 241 var d = new Date(0); 242 d.getTimezoneOffset(); 243 ` 244 245 l := time.Local 246 defer func() { 247 time.Local = l 248 }() 249 var err error 250 time.Local, err = time.LoadLocation("Europe/London") 251 if err != nil { 252 t.Fatal(err) 253 } 254 255 testScript1(SCRIPT, intToValue(-60), t) 256} 257 258func TestDateValueOf(t *testing.T) { 259 const SCRIPT = ` 260 var d9 = new Date(1.23e15); 261 d9.valueOf(); 262 ` 263 264 testScript1(SCRIPT, intToValue(1.23e15), t) 265} 266 267func TestDateSetters(t *testing.T) { 268 const SCRIPT = ` 269 assert.sameValue((new Date(0)).setMilliseconds(2345), 2345, "setMilliseconds(2345)"); 270 assert.sameValue(new Date(1000).setMilliseconds(23450000000000), 23450000001000, "setMilliseconds(23450000000000)"); 271 assert.sameValue((new Date(0)).setUTCMilliseconds(2345), 2345, "setUTCMilliseconds()"); 272 assert.sameValue((new Date(0)).setSeconds(12), 12000, "setSeconds()"); 273 assert.sameValue((new Date(0)).setUTCSeconds(12), 12000, "setUTCSeconds()"); 274 assert.sameValue((new Date(0)).setMinutes(12), 12 * 60 * 1000, "setMinutes()"); 275 assert.sameValue((new Date(0)).setUTCMinutes(12), 12 * 60 * 1000, "setUTCMinutes()"); 276 assert.sameValue((new Date("2016-06-01")).setHours(1), 1464739200000, "setHours()"); 277 assert.sameValue((new Date("2016-06-01")).setUTCHours(1), 1464742800000, "setUTCHours()"); 278 assert.sameValue((new Date(0)).setDate(2), 86400000, "setDate()"); 279 assert.sameValue((new Date(0)).setUTCDate(2), 86400000, "setUTCDate()"); 280 assert.sameValue((new Date(0)).setMonth(2), 5097600000, "setMonth()"); 281 assert.sameValue((new Date(0)).setUTCMonth(2), 5097600000, "setUTCMonth()"); 282 assert.sameValue((new Date(0)).setFullYear(1971), 31536000000, "setFullYear()"); 283 assert.sameValue((new Date(0)).setFullYear(1971, 2, 3), 36806400000, "setFullYear(Y,M,D)"); 284 assert.sameValue((new Date(0)).setUTCFullYear(1971), 31536000000, "setUTCFullYear()"); 285 assert.sameValue((new Date(0)).setUTCFullYear(1971, 2, 3), 36806400000, "setUTCFullYear(Y,M,D)"); 286 287 var d = new Date(); 288 d.setTime(1151877845000); 289 assert.sameValue(d.getHours(), 23, "d.getHours()"); 290 ` 291 292 l := time.Local 293 defer func() { 294 time.Local = l 295 }() 296 var err error 297 time.Local, err = time.LoadLocation("Europe/London") 298 if err != nil { 299 t.Fatal(err) 300 } 301 302 testScript1(TESTLIB+SCRIPT, _undefined, t) 303} 304 305func TestDateParse(t *testing.T) { 306 const SCRIPT = ` 307 var zero = new Date(0); 308 309 assert.sameValue(zero.valueOf(), Date.parse(zero.toString()), 310 "Date.parse(zeroDate.toString())"); 311 assert.sameValue(zero.valueOf(), Date.parse(zero.toUTCString()), 312 "Date.parse(zeroDate.toUTCString())"); 313 assert.sameValue(zero.valueOf(), Date.parse(zero.toISOString()), 314 "Date.parse(zeroDate.toISOString())"); 315 316 function testParse(str, expected) { 317 assert.sameValue(Date.parse(str), expected, str); 318 } 319 320 testParse("Mon, 02 Jan 2006 15:04:05 MST", 1136239445000); 321 testParse("Tue, 22 Jun 2021 13:54:40 GMT", 1624370080000); 322 testParse("Tuesday, 22 Jun 2021 13:54:40 GMT", 1624370080000); 323 testParse("Mon, 02 Jan 2006 15:04:05 GMT-07:00 (MST)", 1136239445000); 324 testParse("Mon, 02 Jan 2006 15:04:05 -07:00 (MST)", 1136239445000); 325 testParse("Monday, 02 Jan 2006 15:04:05 -0700 (MST)", 1136239445000); 326 testParse("Mon Jan 02 2006 15:04:05 GMT-0700 (GMT Standard Time)", 1136239445000); 327 testParse("Mon Jan 2 15:04:05 MST 2006", 1136239445000); 328 testParse("Mon Jan 02 15:04:05 MST 2006", 1136239445000); 329 testParse("Mon Jan 02 15:04:05 -0700 2006", 1136239445000); 330 331 testParse("December 04, 1986", 534038400000); 332 testParse("Dec 04, 1986", 534038400000); 333 testParse("Dec 4, 1986", 534038400000); 334 335 testParse("2006-01-02T15:04:05.000Z", 1136214245000); 336 testParse("2006-06-02T15:04:05.000", 1149275045000); 337 testParse("2006-01-02T15:04:05", 1136232245000); 338 testParse("2006-01-02", 1136160000000); 339 testParse("2006T15:04-0700", 1136153040000); 340 testParse("2006T15:04Z", 1136127840000); 341 testParse("2019-01-01T12:00:00.52Z", 1546344000520); 342 343 var d = new Date("Mon, 02 Jan 2006 15:04:05 MST"); 344 345 assert.sameValue(d.getUTCHours(), 22, 346 "new Date(\"Mon, 02 Jan 2006 15:04:05 MST\").getUTCHours()"); 347 348 assert.sameValue(d.getHours(), 17, 349 "new Date(\"Mon, 02 Jan 2006 15:04:05 MST\").getHours()"); 350 351 assert.sameValue(Date.parse("Mon, 02 Jan 2006 15:04:05 zzz"), NaN, 352 "Date.parse(\"Mon, 02 Jan 2006 15:04:05 zzz\")"); 353 354 assert.sameValue(Date.parse("Mon, 02 Jan 2006 15:04:05 ZZZ"), NaN, 355 "Date.parse(\"Mon, 02 Jan 2006 15:04:05 ZZZ\")"); 356 357 var minDateStr = "-271821-04-20T00:00:00.000Z"; 358 var minDate = new Date(-8640000000000000); 359 360 assert.sameValue(minDate.toISOString(), minDateStr, "minDateStr"); 361 assert.sameValue(Date.parse(minDateStr), minDate.valueOf(), "parse minDateStr"); 362 363 var maxDateStr = "+275760-09-13T00:00:00.000Z"; 364 var maxDate = new Date(8640000000000000); 365 366 assert.sameValue(maxDate.toISOString(), maxDateStr, "maxDateStr"); 367 assert.sameValue(Date.parse(maxDateStr), maxDate.valueOf(), "parse maxDateStr"); 368 369 var belowRange = "-271821-04-19T23:59:59.999Z"; 370 var aboveRange = "+275760-09-13T00:00:00.001Z"; 371 372 assert.sameValue(Date.parse(belowRange), NaN, "parse below minimum time value"); 373 assert.sameValue(Date.parse(aboveRange), NaN, "parse above maximum time value"); 374 ` 375 376 l := time.Local 377 defer func() { 378 time.Local = l 379 }() 380 var err error 381 time.Local, err = time.LoadLocation("America/New_York") 382 if err != nil { 383 t.Fatal(err) 384 } 385 386 testScript1(TESTLIB+SCRIPT, _undefined, t) 387} 388 389func TestDateMaxValues(t *testing.T) { 390 const SCRIPT = ` 391 assert.sameValue((new Date(0)).setUTCMilliseconds(8.64e15), 8.64e15); 392 assert.sameValue((new Date(0)).setUTCSeconds(8640000000000), 8.64e15); 393 assert.sameValue((new Date(0)).setUTCMilliseconds(-8.64e15), -8.64e15); 394 assert.sameValue((new Date(0)).setUTCSeconds(-8640000000000), -8.64e15); 395 ` 396 testScript1(TESTLIB+SCRIPT, _undefined, t) 397} 398 399func TestDateExport(t *testing.T) { 400 vm := New() 401 res, err := vm.RunString(`new Date(1000)`) 402 if err != nil { 403 t.Fatal(err) 404 } 405 exp := res.Export() 406 if d, ok := exp.(time.Time); ok { 407 if d.UnixNano()/1e6 != 1000 { 408 t.Fatalf("Invalid exported date: %v", d) 409 } 410 if loc := d.Location(); loc != time.Local { 411 t.Fatalf("Invalid timezone: %v", loc) 412 } 413 } else { 414 t.Fatalf("Invalid export type: %T", exp) 415 } 416} 417 418func TestDateToJSON(t *testing.T) { 419 const SCRIPT = ` 420 Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) 421 ` 422 testScript1(SCRIPT, intToValue(1), t) 423} 424