Compare commits
No commits in common. "6eeb0f70b9d70a3728baa7d4bbdc3fe81d520206" and "f13cc55ce2d0f01db66bf91c3cd272ab5914a009" have entirely different histories.
6eeb0f70b9
...
f13cc55ce2
4 changed files with 91 additions and 291 deletions
|
@ -26,9 +26,6 @@ num-traits = { version = "0.2.0", optional = true }
|
||||||
log = { version = "0.4.8", optional = true }
|
log = { version = "0.4.8", optional = true }
|
||||||
once_cell = "1.2.0"
|
once_cell = "1.2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
rstest = "0.15.0"
|
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"libquickjs-sys",
|
"libquickjs-sys",
|
||||||
|
|
|
@ -1436,7 +1436,7 @@ static inline int is_digit(int c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_space_like(char c) {
|
static inline int is_space_like(char c) {
|
||||||
return c == ' ' || c == ',' || c == ':' || c == '-' || c == '/';
|
return c == ' ' || c == ',' || c == ':' || c == '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct JSClassShortDef {
|
typedef struct JSClassShortDef {
|
||||||
|
@ -48322,7 +48322,7 @@ static void string_skip_spaces_and_comments(JSString *sp, int *pp) {
|
||||||
int nxt = *pp + 1;
|
int nxt = *pp + 1;
|
||||||
|
|
||||||
// interpret - before a number as a sign rather than a comment char
|
// interpret - before a number as a sign rather than a comment char
|
||||||
if (ch == '-' && nesting == 0 && nxt < sp->len && is_digit(string_get(sp, nxt))) {
|
if (ch == '-' && nxt < sp->len && is_digit(string_get(sp, nxt))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!is_space_like(ch)) {
|
if (!is_space_like(ch)) {
|
||||||
|
@ -48339,10 +48339,12 @@ static void string_skip_spaces_and_comments(JSString *sp, int *pp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BOOL char_eq_ignorecase(char c1, char c2) {
|
static BOOL char_eq_ignorecase(char c1, char c2) {
|
||||||
if ((c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z'))
|
if (c1 == c2) return TRUE;
|
||||||
return (c1 | 0x20) == (c2 | 0x20);
|
|
||||||
return c1 == c2;
|
if (c1 >= 'A' && c1 <= 'Z' && c2 == c1 + 32) return TRUE;
|
||||||
|
if (c1 >= 'a' && c1 <= 'z' && c2 == c1 - 32) return TRUE;
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL string_eq_ignorecase(JSString *s1, int p, const char *s2, int len) {
|
static BOOL string_eq_ignorecase(JSString *s1, int p, const char *s2, int len) {
|
||||||
|
@ -48440,34 +48442,6 @@ static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int string_get_num_timezone(JSString *sp, int *pp, int64_t *pval)
|
|
||||||
{
|
|
||||||
int p = *pp;
|
|
||||||
|
|
||||||
int64_t o;
|
|
||||||
if (string_get_signed_digits(sp, &p, &o))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (o < -9959 || o > 9959) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sgn = (o < 0) ? -1 : 1;
|
|
||||||
o = abs((int32_t) o);
|
|
||||||
|
|
||||||
if (string_get(sp, p) != ':') {
|
|
||||||
*pval = ((o / 100) * 60 + (o % 100)) * sgn;
|
|
||||||
} else {
|
|
||||||
p++;
|
|
||||||
int64_t o2;
|
|
||||||
if (string_get_digits(sp, &p, &o2))
|
|
||||||
return -1;
|
|
||||||
*pval = (o * 60 + o2) * sgn;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pp = p;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int find_abbrev(JSString *sp, int p, const char *list, int count) {
|
static int find_abbrev(JSString *sp, int p, const char *list, int count) {
|
||||||
int n, i;
|
int n, i;
|
||||||
|
@ -48522,18 +48496,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
|
|
||||||
sp = JS_VALUE_GET_STRING(s);
|
sp = JS_VALUE_GET_STRING(s);
|
||||||
p = 0;
|
p = 0;
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) {
|
||||||
|
|
||||||
int end_of_digits = p;
|
|
||||||
if (string_get(sp, end_of_digits) == '+' || string_get(sp, end_of_digits) == '-') {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
while (end_of_digits < sp->len && is_digit(string_get(sp, end_of_digits))) {
|
|
||||||
end_of_digits++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((end_of_digits - p) > 0 &&
|
|
||||||
(string_get(sp, end_of_digits) == '-' || string_get(sp, end_of_digits) == 'T')) {
|
|
||||||
/* ISO format */
|
/* ISO format */
|
||||||
/* year field can be negative */
|
/* year field can be negative */
|
||||||
if (string_get_signed_digits(sp, &p, &fields[0]))
|
if (string_get_signed_digits(sp, &p, &fields[0]))
|
||||||
|
@ -48543,28 +48506,23 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
if (p >= sp->len)
|
if (p >= sp->len)
|
||||||
break;
|
break;
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case 1: // Year
|
case 1:
|
||||||
case 2: // Month
|
case 2:
|
||||||
c = '-';
|
c = '-';
|
||||||
break;
|
break;
|
||||||
case 3: // Day
|
case 3:
|
||||||
c = 'T';
|
c = 'T';
|
||||||
break;
|
break;
|
||||||
case 4: // Hour
|
case 4:
|
||||||
case 5: // Minute
|
case 5:
|
||||||
c = ':';
|
c = ':';
|
||||||
break;
|
break;
|
||||||
case 6: // Second
|
case 6:
|
||||||
c = '.';
|
c = '.';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (string_get(sp, p) != c) {
|
if (string_get(sp, p) != c)
|
||||||
// 2000T08:00Z
|
break;
|
||||||
if (i < 3 && string_get(sp, p) == 'T') {
|
|
||||||
i = 3;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
p++;
|
p++;
|
||||||
if (i == 6) {
|
if (i == 6) {
|
||||||
if (string_get_milliseconds(sp, &p, &fields[i]))
|
if (string_get_milliseconds(sp, &p, &fields[i]))
|
||||||
|
@ -48574,9 +48532,6 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Hour only is invalid
|
|
||||||
if (i == 4) goto done;
|
|
||||||
|
|
||||||
/* no time: UTC by default */
|
/* no time: UTC by default */
|
||||||
is_local = (i > 3);
|
is_local = (i > 3);
|
||||||
fields[1] -= 1;
|
fields[1] -= 1;
|
||||||
|
@ -48624,7 +48579,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
if (p - word_start >= 3) {
|
if (p - word_start >= 3) {
|
||||||
month = find_abbrev(sp, word_start, month_names, 12);
|
month = find_abbrev(sp, word_start, month_names, 12);
|
||||||
}
|
}
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
string_skip_spaces_and_comments(sp, &p); // and comments
|
||||||
word_start = p;
|
word_start = p;
|
||||||
} else {
|
} else {
|
||||||
p++;
|
p++;
|
||||||
|
@ -48638,7 +48593,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
month = find_abbrev(sp, word_start, month_names, 12);
|
month = find_abbrev(sp, word_start, month_names, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
string_skip_spaces_and_comments(sp, &p); // and comments
|
||||||
if (sp->len <= p)
|
if (sp->len <= p)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
@ -48647,7 +48602,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
if (string_get_digits(sp, &p, &day))
|
if (string_get_digits(sp, &p, &day))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
int64_t year = -1;
|
int64_t year = 0;
|
||||||
if (day > 31) {
|
if (day > 31) {
|
||||||
if (string_get(sp, p) != '/')
|
if (string_get(sp, p) != '/')
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -48676,7 +48631,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
if (string_get_digits(sp, &p, &day))
|
if (string_get_digits(sp, &p, &day))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!is_space_like(string_get(sp, p)))
|
if (string_get(sp, p) != '/')
|
||||||
goto done;
|
goto done;
|
||||||
p++;
|
p++;
|
||||||
if (sp->len <= p)
|
if (sp->len <= p)
|
||||||
|
@ -48685,31 +48640,40 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
if (string_get(sp, p) == '-') {
|
if (string_get(sp, p) == '-') {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
string_skip_spaces_and_comments(sp, &p); // and comments
|
||||||
|
|
||||||
|
if (string_get(sp, p) == ',') {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
// Jan,2000,08:00:00 UT
|
|
||||||
if (month == -1) {
|
if (month == -1) {
|
||||||
month = find_abbrev(sp, p, month_names, 12);
|
month = find_abbrev(sp, p, month_names, 12);
|
||||||
if (month == -1)
|
if (month == -1)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
while (p < sp->len && !is_space_like(string_get(sp, p))) {
|
while (p < sp->len && string_get(sp, p) != '-' && string_get(sp, p) != ' ') {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if (sp->len <= p)
|
if (sp->len <= p)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
// '-99 23:12:40 GMT'
|
||||||
|
if (string_get(sp, p) != '-' && string_get(sp, p) != '/' && string_get(sp, p) != ' ') {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (month < 0 || month > 11) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
if (year <= 0) {
|
||||||
|
|
||||||
if (year < 0) {
|
|
||||||
// Year following, e.g. 01 Jan 2000 08:00:00 UT
|
|
||||||
// Time following, e.g. Jan 01 08:00:00 UT 2000
|
|
||||||
if (sp->len <= p + 2 || string_get(sp, p + 2) != ':') {
|
|
||||||
if (string_get_digits(sp, &p, &year))
|
if (string_get_digits(sp, &p, &year))
|
||||||
goto done;
|
goto done;
|
||||||
|
if (year <= 0) {
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48725,7 +48689,9 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
year = -1;
|
year = -1;
|
||||||
} else if (is_space_like(string_get(sp, p))) {
|
} else if (is_space_like(string_get(sp, p))) {
|
||||||
p++;
|
p++;
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
string_skip_spaces_and_comments(sp, &p); // and comments
|
||||||
|
} else {
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a number? If not, this might be a timezone name.
|
// Read a number? If not, this might be a timezone name.
|
||||||
|
@ -48746,6 +48712,10 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
if (string_get_digits(sp, &p, &minute))
|
if (string_get_digits(sp, &p, &minute))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
if (minute < 0 || minute > 59) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
// ':40 GMT'
|
// ':40 GMT'
|
||||||
// seconds are optional in rfc822 + rfc2822
|
// seconds are optional in rfc822 + rfc2822
|
||||||
if (string_get(sp, p) == ':') {
|
if (string_get(sp, p) == ':') {
|
||||||
|
@ -48754,6 +48724,10 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
if (string_get_digits(sp, &p, &second))
|
if (string_get_digits(sp, &p, &second))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
if (second < 0 || second > 59) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
// disallow trailing colon seconds
|
// disallow trailing colon seconds
|
||||||
if (string_get(sp, p) == ':') {
|
if (string_get(sp, p) == ':') {
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -48762,7 +48736,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
string_skip_spaces_and_comments(sp, &p); // and comments
|
||||||
|
|
||||||
if (string_eq_ignorecase(sp, p, "AM", 2)) {
|
if (string_eq_ignorecase(sp, p, "AM", 2)) {
|
||||||
if (hour > 12) {
|
if (hour > 12) {
|
||||||
|
@ -48772,7 +48746,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
hour = 0;
|
hour = 0;
|
||||||
}
|
}
|
||||||
p += 2;
|
p += 2;
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
string_skip_spaces_and_comments(sp, &p); // and comments
|
||||||
} else if (string_eq_ignorecase(sp, p, "PM", 2)) {
|
} else if (string_eq_ignorecase(sp, p, "PM", 2)) {
|
||||||
if (hour > 12) {
|
if (hour > 12) {
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -48781,7 +48755,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
hour += 12;
|
hour += 12;
|
||||||
}
|
}
|
||||||
p += 2;
|
p += 2;
|
||||||
string_skip_spaces_and_comments(sp, &p);
|
string_skip_spaces_and_comments(sp, &p); // and comments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48790,8 +48764,26 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
// Some websites omit the time zone
|
// Some websites omit the time zone
|
||||||
if (sp->len > p) {
|
if (sp->len > p) {
|
||||||
if (string_get(sp, p) == '+' || string_get(sp, p) == '-') {
|
if (string_get(sp, p) == '+' || string_get(sp, p) == '-') {
|
||||||
if (string_get_num_timezone(sp, &p, &tz))
|
int64_t o;
|
||||||
|
if (string_get_digits(sp, &p, &o))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
if (o < -9959 || o > 9959) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sgn = (o < 0) ? -1 : 1;
|
||||||
|
o = abs((int32_t) o);
|
||||||
|
|
||||||
|
if (string_get(sp, p) != ':') {
|
||||||
|
tz = ((o / 100) * 60 + (o % 100)) * sgn;
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
int64_t o2;
|
||||||
|
if (string_get_digits(sp, &p, &o2))
|
||||||
|
goto done;
|
||||||
|
tz = (o * 60 + o2) * sgn;
|
||||||
|
}
|
||||||
is_local = FALSE;
|
is_local = FALSE;
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < sizeof(known_zones) / sizeof(struct KnownZone); i++) {
|
for (int i = 0; i < sizeof(known_zones) / sizeof(struct KnownZone); i++) {
|
||||||
|
@ -48799,15 +48791,6 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
tz = known_zones[i].tzOffset;
|
tz = known_zones[i].tzOffset;
|
||||||
p += strlen(known_zones[i].tzName);
|
p += strlen(known_zones[i].tzName);
|
||||||
is_local = FALSE;
|
is_local = FALSE;
|
||||||
|
|
||||||
// TZ offset (GMT+0)
|
|
||||||
if (string_get(sp, p) == '+' || string_get(sp, p) == '-') {
|
|
||||||
int64_t o;
|
|
||||||
if (string_get_num_timezone(sp, &p, &o))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
tz += o;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48845,16 +48828,6 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
|
||||||
fields[5] = second;
|
fields[5] = second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate fields
|
|
||||||
if (fields[1] < 0 || fields[1] > 11 ||
|
|
||||||
fields[2] < 1 || fields[2] > 31 ||
|
|
||||||
fields[3] < 0 || fields[3] > 24 ||
|
|
||||||
fields[4] < 0 || fields[4] > 59 ||
|
|
||||||
fields[5] < 0 || fields[5] > 59 ||
|
|
||||||
fields[6] < 0 || fields[6] > 999 ||
|
|
||||||
fields[3] * 3600 * 1000 + fields[4] * 60000 + fields[5] * 1000 + fields[6] > 24 * 3600 * 1000
|
|
||||||
) goto done;
|
|
||||||
|
|
||||||
for(i = 0; i < 7; i++)
|
for(i = 0; i < 7; i++)
|
||||||
fields1[i] = fields[i];
|
fields1[i] = fields[i];
|
||||||
d = set_date_fields(fields1, is_local) - (tz * 60000);
|
d = set_date_fields(fields1, is_local) - (tz * 60000);
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
//! "#).unwrap();
|
//! "#).unwrap();
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
mod bindings;
|
mod bindings;
|
||||||
|
|
199
src/tests.rs
199
src/tests.rs
|
@ -1,6 +1,7 @@
|
||||||
use std::{collections::HashMap, convert::TryInto};
|
use std::{collections::HashMap, convert::TryInto};
|
||||||
|
|
||||||
use rstest::rstest;
|
#[cfg(feature = "chrono")]
|
||||||
|
use chrono::{Date, DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -625,162 +626,9 @@ fn test_global_setter() {
|
||||||
ctx.eval("a + 1").unwrap();
|
ctx.eval("a + 1").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test suite was taken from V8
|
#[cfg(feature = "chrono")]
|
||||||
// Source: https://github.com/v8/v8/blob/9433ad119aadfe10d60935029195c31f25ab8624/test/mjsunit/date-parse.js
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
// testCasesES5Misc
|
|
||||||
#[case("2000-01-01T08:00:00.000Z", 946713600000)]
|
|
||||||
#[case("2000-01-01T08:00:00Z", 946713600000)]
|
|
||||||
#[case("2000-01-01T08:00Z", 946713600000)]
|
|
||||||
#[case("2000-01T08:00:00.000Z", 946713600000)]
|
|
||||||
#[case("2000T08:00:00.000Z", 946713600000)]
|
|
||||||
#[case("2000T08:00Z", 946713600000)]
|
|
||||||
#[case("2000-01T00:00:00.000-08:00", 946713600000)]
|
|
||||||
#[case("2000-01T08:00:00.001Z", 946713600001)]
|
|
||||||
#[case("2000-01T08:00:00.099Z", 946713600099)]
|
|
||||||
#[case("2000-01T08:00:00.999Z", 946713600999)]
|
|
||||||
#[case("2000-01T00:00:00.001-08:00", 946713600001)]
|
|
||||||
#[case("2000-01-01T24:00Z", 946771200000)]
|
|
||||||
#[case("2000-01-01T24:00:00Z", 946771200000)]
|
|
||||||
#[case("2000-01-01T24:00:00.000Z", 946771200000)]
|
|
||||||
fn test_date_iso(#[case] input: &str, #[case] expect: i64) {
|
|
||||||
let ctx = Context::new().unwrap();
|
|
||||||
let res = ctx
|
|
||||||
.eval(&format!(r#"new Date("{}").getTime()"#, input))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let n: f64 = res.try_into().unwrap();
|
|
||||||
assert_eq!(n, expect as f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
#[case("Sat, 01-Jan-2000 08:00:00 GMT", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 08:00:00 GMT+0", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 08:00:00 GMT+00", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 08:00:00 GMT+000", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 08:00:00 GMT+0000", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 08:00:00 GMT+00:00", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 08:00:00 GMT", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 08:00:00 GMT", 946713600000)]
|
|
||||||
#[case("01 Jan 00 08:00 -0000", 946713600000)]
|
|
||||||
#[case("01 Jan 00 08:00 +0000", 946713600000)]
|
|
||||||
fn test_date_gmt(#[case] input: &str, #[case] expect: i64) {
|
|
||||||
let ctx = Context::new().unwrap();
|
|
||||||
let res = ctx
|
|
||||||
.eval(&format!(r#"new Date("{}").getTime()"#, input))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let n: f64 = res.try_into().unwrap();
|
|
||||||
assert_eq!(n, expect as f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
// EST (-5:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 03:00:00 UTC-0500", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 03:00:00 UTC-05:00", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 03:00:00 EST", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 03:00:00 EST", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 03:00:00 EST", 946713600000)]
|
|
||||||
#[case("01 Jan 00 03:00 -0500", 946713600000)]
|
|
||||||
// EDT (-4:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 04:00:00 EDT", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 04:00:00 EDT", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 04:00:00 EDT", 946713600000)]
|
|
||||||
#[case("01 Jan 00 04:00 -0400", 946713600000)]
|
|
||||||
// CST (-6:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 02:00:00 CST", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 02:00:00 CST", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 02:00:00 CST", 946713600000)]
|
|
||||||
#[case("01 Jan 00 02:00 -0600", 946713600000)]
|
|
||||||
// CDT (-5:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 03:00:00 CDT", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 03:00:00 CDT", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 03:00:00 CDT", 946713600000)]
|
|
||||||
#[case("01 Jan 00 03:00 -0500", 946713600000)]
|
|
||||||
// MST (-7:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 01:00:00 MST", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 01:00:00 MST", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 01:00:00 MST", 946713600000)]
|
|
||||||
#[case("01 Jan 00 01:00 -0700", 946713600000)]
|
|
||||||
// MDT (-6:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 02:00:00 MDT", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 02:00:00 MDT", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 02:00:00 MDT", 946713600000)]
|
|
||||||
#[case("01 Jan 00 02:00 -0600", 946713600000)]
|
|
||||||
// PST (-8:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 00:00:00 PST", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 00:00:00 PST", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 00:00:00 PST", 946713600000)]
|
|
||||||
#[case("01 Jan 00 00:00 -0800", 946713600000)]
|
|
||||||
#[case("Sat, 01-Jan-2000 PST", 946713600000)]
|
|
||||||
// PDT (-7:00)
|
|
||||||
#[case("Sat, 01-Jan-2000 01:00:00 PDT", 946713600000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 01:00:00 PDT", 946713600000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 01:00:00 PDT", 946713600000)]
|
|
||||||
#[case("01 Jan 00 01:00 -0700", 946713600000)]
|
|
||||||
fn test_date_tz(#[case] input: &str, #[case] expect: i64) {
|
|
||||||
let ctx = Context::new().unwrap();
|
|
||||||
let res = ctx
|
|
||||||
.eval(&format!(r#"new Date("{}").getTime()"#, input))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let n: f64 = res.try_into().unwrap();
|
|
||||||
assert_eq!(n, expect as f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
// Special handling for years in the [0, 100) range.
|
|
||||||
#[case("Sat, 01 Jan 0 08:00:00 UT", 946713600000)] // year 2000
|
|
||||||
#[case("Sat, 01 Jan 49 08:00:00 UT", 2493100800000)] // year 2049
|
|
||||||
#[case("Sat, 01 Jan 50 08:00:00 UT", -631123200000)] // year 1950
|
|
||||||
#[case("Sat, 01 Jan 99 08:00:00 UT", 915177600000)] // year 1999
|
|
||||||
#[case("Sat, 01 Jan 100 08:00:00 UT", -59011430400000)] // year 100
|
|
||||||
// Test PM after time.
|
|
||||||
#[case("Sat, 01-Jan-2000 08:00 PM UT", 946756800000)]
|
|
||||||
#[case("Sat, 01 Jan 2000 08:00 PM UT", 946756800000)]
|
|
||||||
#[case("Jan 01 2000 08:00 PM UT", 946756800000)]
|
|
||||||
#[case("Jan 01 08:00 PM UT 2000", 946756800000)]
|
|
||||||
#[case("Saturday, 01-Jan-00 08:00 PM UT", 946756800000)]
|
|
||||||
#[case("01 Jan 00 08:00 PM +0000", 946756800000)]
|
|
||||||
fn test_date_special(#[case] input: &str, #[case] expect: i64) {
|
|
||||||
let ctx = Context::new().unwrap();
|
|
||||||
let res = ctx
|
|
||||||
.eval(&format!(r#"new Date("{}").getTime()"#, input))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let n: f64 = res.try_into().unwrap();
|
|
||||||
assert_eq!(n, expect as f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
#[case("2000-01-01TZ")]
|
|
||||||
#[case("2000-01-01T60Z")]
|
|
||||||
#[case("2000-01-01T60:60Z")]
|
|
||||||
#[case("2000-01-0108:00Z")]
|
|
||||||
#[case("2000-01-01T08Z")]
|
|
||||||
#[case("2000-01-01T24:01")]
|
|
||||||
#[case("2000-01-01T24:00:01")]
|
|
||||||
#[case("2000-01-01T24:00:00.001")]
|
|
||||||
#[case("2000-01-01T24:00:00.999Z")]
|
|
||||||
#[case("May 25 2008 1:30 (PM)) UTC")]
|
|
||||||
#[case("May 25 2008 1:30( )AM (PM)")]
|
|
||||||
#[case("a1")]
|
|
||||||
#[case("nasfdjklsfjoaifg1")]
|
|
||||||
#[case("x_2")]
|
|
||||||
#[case("May 25 2008 AAA (GMT)")]
|
|
||||||
fn test_date_invalid(#[case] input: &str) {
|
|
||||||
let ctx = Context::new().unwrap();
|
|
||||||
let res = ctx
|
|
||||||
.eval(&format!(r#"new Date("{}").getTime()"#, input))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let n: f64 = res.try_into().unwrap();
|
|
||||||
assert!(n.is_nan(), "got: {}", n);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_ut() {
|
fn test_ut() {
|
||||||
let test_cases_ut = vec![
|
let test_cases_ut = vec![
|
||||||
"Sat, 01-Jan-2000 08:00:00 UT",
|
"Sat, 01-Jan-2000 08:00:00 UT",
|
||||||
"Sat, 01 Jan 2000 08:00:00 UT",
|
"Sat, 01 Jan 2000 08:00:00 UT",
|
||||||
|
@ -850,20 +698,27 @@ fn test_date_ut() {
|
||||||
" 01 Jan 00 08:00 +0000()((asfd)(Sat, 01-Jan-2000)) ",
|
" 01 Jan 00 08:00 +0000()((asfd)(Sat, 01-Jan-2000)) ",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let expected = JsValue::Date(DateTime::from_utc(
|
||||||
|
NaiveDateTime::new(
|
||||||
|
NaiveDate::from_ymd(2000, 1, 1),
|
||||||
|
NaiveTime::from_hms(8, 0, 0),
|
||||||
|
),
|
||||||
|
Utc,
|
||||||
|
));
|
||||||
|
|
||||||
let mut passed = 0;
|
let mut passed = 0;
|
||||||
let mut failed = 0;
|
let mut failed = 0;
|
||||||
|
|
||||||
for case in test_cases_ut {
|
for case in test_cases_ut {
|
||||||
let ctx = Context::new().unwrap();
|
let ctx = Context::new().unwrap();
|
||||||
let res = ctx
|
let res = ctx
|
||||||
.eval(&format!(r#"new Date("{}").getTime()"#, case))
|
.eval(&format!(r#"new Date("{}")"#, case))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let n: f64 = res.try_into().unwrap();
|
|
||||||
|
|
||||||
if n == 946713600000.0 {
|
if res == expected {
|
||||||
passed += 1;
|
passed += 1;
|
||||||
} else {
|
} else {
|
||||||
println!("FAIL: `{}` - {}", case, n);
|
println!("FAIL: `{}` - {:?}", case, res);
|
||||||
failed += 1;
|
failed += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,27 +726,3 @@ fn test_date_ut() {
|
||||||
println!("{}/{} Passed", passed, passed + failed);
|
println!("{}/{} Passed", passed, passed + failed);
|
||||||
assert_eq!(failed, 0);
|
assert_eq!(failed, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
// Test if the JS interpreter can parse its own date format
|
|
||||||
// (Dates from 1970 to ~2070 with 150h steps.)
|
|
||||||
fn test_date_selfparse() {
|
|
||||||
let ctx = Context::new().unwrap();
|
|
||||||
let res = ctx
|
|
||||||
.eval(
|
|
||||||
r#"
|
|
||||||
test = () => {
|
|
||||||
for (var i = 0; i < 24 * 365 * 100; i += 150) {
|
|
||||||
var ms = i * (3600 * 1000);
|
|
||||||
var s = (new Date(ms)).toString();
|
|
||||||
if(ms != Date.parse(s)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
test();
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let res: bool = res.try_into().unwrap();
|
|
||||||
assert!(res);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue