mirror of
https://github.com/bellard/quickjs.git
synced 2024-11-23 06:08:13 +08:00
2ecaf6cf97
1. Refactor JSObject weak reference list to support different kind of weak reference 2. Support Symbol as WeakMap key
913 lines
25 KiB
JavaScript
913 lines
25 KiB
JavaScript
"use strict";
|
|
|
|
var status = 0;
|
|
var throw_errors = true;
|
|
|
|
function throw_error(msg) {
|
|
if (throw_errors)
|
|
throw Error(msg);
|
|
console.log(msg);
|
|
status = 1;
|
|
}
|
|
|
|
function assert(actual, expected, message) {
|
|
function get_full_type(o) {
|
|
var type = typeof(o);
|
|
if (type === 'object') {
|
|
if (o === null)
|
|
return 'null';
|
|
if (o.constructor && o.constructor.name)
|
|
return o.constructor.name;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
if (arguments.length == 1)
|
|
expected = true;
|
|
|
|
if (typeof actual === typeof expected) {
|
|
if (actual === expected) {
|
|
if (actual !== 0 || (1 / actual) === (1 / expected))
|
|
return;
|
|
}
|
|
if (typeof actual === 'number') {
|
|
if (isNaN(actual) && isNaN(expected))
|
|
return true;
|
|
}
|
|
if (typeof actual === 'object') {
|
|
if (actual !== null && expected !== null
|
|
&& actual.constructor === expected.constructor
|
|
&& actual.toString() === expected.toString())
|
|
return;
|
|
}
|
|
}
|
|
// Should output the source file and line number and extract
|
|
// the expression from the assert call
|
|
throw_error("assertion failed: got " +
|
|
get_full_type(actual) + ":|" + actual + "|, expected " +
|
|
get_full_type(expected) + ":|" + expected + "|" +
|
|
(message ? " (" + message + ")" : ""));
|
|
}
|
|
|
|
function assert_throws(expected_error, func)
|
|
{
|
|
var err = false;
|
|
try {
|
|
func();
|
|
} catch(e) {
|
|
err = true;
|
|
if (!(e instanceof expected_error)) {
|
|
// Should output the source file and line number and extract
|
|
// the expression from the assert_throws() call
|
|
throw_error("unexpected exception type");
|
|
return;
|
|
}
|
|
}
|
|
if (!err) {
|
|
// Should output the source file and line number and extract
|
|
// the expression from the assert_throws() call
|
|
throw_error("expected exception");
|
|
}
|
|
}
|
|
|
|
// load more elaborate version of assert if available
|
|
try { __loadScript("test_assert.js"); } catch(e) {}
|
|
|
|
/*----------------*/
|
|
|
|
function my_func(a, b)
|
|
{
|
|
return a + b;
|
|
}
|
|
|
|
function test_function()
|
|
{
|
|
function f(a, b) {
|
|
var i, tab = [];
|
|
tab.push(this);
|
|
for(i = 0; i < arguments.length; i++)
|
|
tab.push(arguments[i]);
|
|
return tab;
|
|
}
|
|
function constructor1(a) {
|
|
this.x = a;
|
|
}
|
|
|
|
var r, g;
|
|
|
|
r = my_func.call(null, 1, 2);
|
|
assert(r, 3, "call");
|
|
|
|
r = my_func.apply(null, [1, 2]);
|
|
assert(r, 3, "apply");
|
|
|
|
r = (function () { return 1; }).apply(null, undefined);
|
|
assert(r, 1);
|
|
|
|
assert_throws(TypeError, (function() {
|
|
Reflect.apply((function () { return 1; }), null, undefined);
|
|
}));
|
|
|
|
r = new Function("a", "b", "return a + b;");
|
|
assert(r(2,3), 5, "function");
|
|
|
|
g = f.bind(1, 2);
|
|
assert(g.length, 1);
|
|
assert(g.name, "bound f");
|
|
assert(g(3), [1,2,3]);
|
|
|
|
g = constructor1.bind(null, 1);
|
|
r = new g();
|
|
assert(r.x, 1);
|
|
}
|
|
|
|
function test()
|
|
{
|
|
var r, a, b, c, err;
|
|
|
|
r = Error("hello");
|
|
assert(r.message, "hello", "Error");
|
|
|
|
a = new Object();
|
|
a.x = 1;
|
|
assert(a.x, 1, "Object");
|
|
|
|
assert(Object.getPrototypeOf(a), Object.prototype, "getPrototypeOf");
|
|
Object.defineProperty(a, "y", { value: 3, writable: true, configurable: true, enumerable: true });
|
|
assert(a.y, 3, "defineProperty");
|
|
|
|
Object.defineProperty(a, "z", { get: function () { return 4; }, set: function(val) { this.z_val = val; }, configurable: true, enumerable: true });
|
|
assert(a.z, 4, "get");
|
|
a.z = 5;
|
|
assert(a.z_val, 5, "set");
|
|
|
|
a = { get z() { return 4; }, set z(val) { this.z_val = val; } };
|
|
assert(a.z, 4, "get");
|
|
a.z = 5;
|
|
assert(a.z_val, 5, "set");
|
|
|
|
b = Object.create(a);
|
|
assert(Object.getPrototypeOf(b), a, "create");
|
|
c = {u:2};
|
|
/* XXX: refcount bug in 'b' instead of 'a' */
|
|
Object.setPrototypeOf(a, c);
|
|
assert(Object.getPrototypeOf(a), c, "setPrototypeOf");
|
|
|
|
a = {};
|
|
assert(a.toString(), "[object Object]", "toString");
|
|
|
|
a = {x:1};
|
|
assert(Object.isExtensible(a), true, "extensible");
|
|
Object.preventExtensions(a);
|
|
|
|
err = false;
|
|
try {
|
|
a.y = 2;
|
|
} catch(e) {
|
|
err = true;
|
|
}
|
|
assert(Object.isExtensible(a), false, "extensible");
|
|
assert(typeof a.y, "undefined", "extensible");
|
|
assert(err, true, "extensible");
|
|
}
|
|
|
|
function test_enum()
|
|
{
|
|
var a, tab;
|
|
a = {x:1,
|
|
"18014398509481984": 1,
|
|
"9007199254740992": 1,
|
|
"9007199254740991": 1,
|
|
"4294967296": 1,
|
|
"4294967295": 1,
|
|
y:1,
|
|
"4294967294": 1,
|
|
"1": 2};
|
|
tab = Object.keys(a);
|
|
// console.log("tab=" + tab.toString());
|
|
assert(tab, ["1","4294967294","x","18014398509481984","9007199254740992","9007199254740991","4294967296","4294967295","y"], "keys");
|
|
}
|
|
|
|
function test_array()
|
|
{
|
|
var a, err;
|
|
|
|
a = [1, 2, 3];
|
|
assert(a.length, 3, "array");
|
|
assert(a[2], 3, "array1");
|
|
|
|
a = new Array(10);
|
|
assert(a.length, 10, "array2");
|
|
|
|
a = new Array(1, 2);
|
|
assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array3");
|
|
|
|
a = [1, 2, 3];
|
|
a.length = 2;
|
|
assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array4");
|
|
|
|
a = [];
|
|
a[1] = 10;
|
|
a[4] = 3;
|
|
assert(a.length, 5);
|
|
|
|
a = [1,2];
|
|
a.length = 5;
|
|
a[4] = 1;
|
|
a.length = 4;
|
|
assert(a[4] !== 1, true, "array5");
|
|
|
|
a = [1,2];
|
|
a.push(3,4);
|
|
assert(a.join(), "1,2,3,4", "join");
|
|
|
|
a = [1,2,3,4,5];
|
|
Object.defineProperty(a, "3", { configurable: false });
|
|
err = false;
|
|
try {
|
|
a.length = 2;
|
|
} catch(e) {
|
|
err = true;
|
|
}
|
|
assert(err && a.toString() === "1,2,3,4");
|
|
}
|
|
|
|
function test_string()
|
|
{
|
|
var a;
|
|
a = String("abc");
|
|
assert(a.length, 3, "string");
|
|
assert(a[1], "b", "string");
|
|
assert(a.charCodeAt(1), 0x62, "string");
|
|
assert(String.fromCharCode(65), "A", "string");
|
|
assert(String.fromCharCode.apply(null, [65, 66, 67]), "ABC", "string");
|
|
assert(a.charAt(1), "b");
|
|
assert(a.charAt(-1), "");
|
|
assert(a.charAt(3), "");
|
|
|
|
a = "abcd";
|
|
assert(a.substring(1, 3), "bc", "substring");
|
|
a = String.fromCharCode(0x20ac);
|
|
assert(a.charCodeAt(0), 0x20ac, "unicode");
|
|
assert(a, "€", "unicode");
|
|
assert(a, "\u20ac", "unicode");
|
|
assert(a, "\u{20ac}", "unicode");
|
|
assert("a", "\x61", "unicode");
|
|
|
|
a = "\u{10ffff}";
|
|
assert(a.length, 2, "unicode");
|
|
assert(a, "\u{dbff}\u{dfff}", "unicode");
|
|
assert(a.codePointAt(0), 0x10ffff);
|
|
assert(String.fromCodePoint(0x10ffff), a);
|
|
|
|
assert("a".concat("b", "c"), "abc");
|
|
|
|
assert("abcabc".indexOf("cab"), 2);
|
|
assert("abcabc".indexOf("cab2"), -1);
|
|
assert("abc".indexOf("c"), 2);
|
|
|
|
assert("aaa".indexOf("a"), 0);
|
|
assert("aaa".indexOf("a", NaN), 0);
|
|
assert("aaa".indexOf("a", -Infinity), 0);
|
|
assert("aaa".indexOf("a", -1), 0);
|
|
assert("aaa".indexOf("a", -0), 0);
|
|
assert("aaa".indexOf("a", 0), 0);
|
|
assert("aaa".indexOf("a", 1), 1);
|
|
assert("aaa".indexOf("a", 2), 2);
|
|
assert("aaa".indexOf("a", 3), -1);
|
|
assert("aaa".indexOf("a", 4), -1);
|
|
assert("aaa".indexOf("a", Infinity), -1);
|
|
|
|
assert("aaa".indexOf(""), 0);
|
|
assert("aaa".indexOf("", NaN), 0);
|
|
assert("aaa".indexOf("", -Infinity), 0);
|
|
assert("aaa".indexOf("", -1), 0);
|
|
assert("aaa".indexOf("", -0), 0);
|
|
assert("aaa".indexOf("", 0), 0);
|
|
assert("aaa".indexOf("", 1), 1);
|
|
assert("aaa".indexOf("", 2), 2);
|
|
assert("aaa".indexOf("", 3), 3);
|
|
assert("aaa".indexOf("", 4), 3);
|
|
assert("aaa".indexOf("", Infinity), 3);
|
|
|
|
assert("aaa".lastIndexOf("a"), 2);
|
|
assert("aaa".lastIndexOf("a", NaN), 2);
|
|
assert("aaa".lastIndexOf("a", -Infinity), 0);
|
|
assert("aaa".lastIndexOf("a", -1), 0);
|
|
assert("aaa".lastIndexOf("a", -0), 0);
|
|
assert("aaa".lastIndexOf("a", 0), 0);
|
|
assert("aaa".lastIndexOf("a", 1), 1);
|
|
assert("aaa".lastIndexOf("a", 2), 2);
|
|
assert("aaa".lastIndexOf("a", 3), 2);
|
|
assert("aaa".lastIndexOf("a", 4), 2);
|
|
assert("aaa".lastIndexOf("a", Infinity), 2);
|
|
|
|
assert("aaa".lastIndexOf(""), 3);
|
|
assert("aaa".lastIndexOf("", NaN), 3);
|
|
assert("aaa".lastIndexOf("", -Infinity), 0);
|
|
assert("aaa".lastIndexOf("", -1), 0);
|
|
assert("aaa".lastIndexOf("", -0), 0);
|
|
assert("aaa".lastIndexOf("", 0), 0);
|
|
assert("aaa".lastIndexOf("", 1), 1);
|
|
assert("aaa".lastIndexOf("", 2), 2);
|
|
assert("aaa".lastIndexOf("", 3), 3);
|
|
assert("aaa".lastIndexOf("", 4), 3);
|
|
assert("aaa".lastIndexOf("", Infinity), 3);
|
|
|
|
assert("a,b,c".split(","), ["a","b","c"]);
|
|
assert(",b,c".split(","), ["","b","c"]);
|
|
assert("a,b,".split(","), ["a","b",""]);
|
|
|
|
assert("aaaa".split(), [ "aaaa" ]);
|
|
assert("aaaa".split(undefined, 0), [ ]);
|
|
assert("aaaa".split(""), [ "a", "a", "a", "a" ]);
|
|
assert("aaaa".split("", 0), [ ]);
|
|
assert("aaaa".split("", 1), [ "a" ]);
|
|
assert("aaaa".split("", 2), [ "a", "a" ]);
|
|
assert("aaaa".split("a"), [ "", "", "", "", "" ]);
|
|
assert("aaaa".split("a", 2), [ "", "" ]);
|
|
assert("aaaa".split("aa"), [ "", "", "" ]);
|
|
assert("aaaa".split("aa", 0), [ ]);
|
|
assert("aaaa".split("aa", 1), [ "" ]);
|
|
assert("aaaa".split("aa", 2), [ "", "" ]);
|
|
assert("aaaa".split("aaa"), [ "", "a" ]);
|
|
assert("aaaa".split("aaaa"), [ "", "" ]);
|
|
assert("aaaa".split("aaaaa"), [ "aaaa" ]);
|
|
assert("aaaa".split("aaaaa", 0), [ ]);
|
|
assert("aaaa".split("aaaaa", 1), [ "aaaa" ]);
|
|
|
|
assert(eval('"\0"'), "\0");
|
|
|
|
assert("abc".padStart(Infinity, ""), "abc");
|
|
}
|
|
|
|
function test_math()
|
|
{
|
|
var a;
|
|
a = 1.4;
|
|
assert(Math.floor(a), 1);
|
|
assert(Math.ceil(a), 2);
|
|
assert(Math.imul(0x12345678, 123), -1088058456);
|
|
assert(Math.imul(0xB505, 0xB504), 2147441940);
|
|
assert(Math.imul(0xB505, 0xB505), -2147479015);
|
|
assert(Math.imul((-2)**31, (-2)**31), 0);
|
|
assert(Math.imul(2**31-1, 2**31-1), 1);
|
|
assert(Math.fround(0.1), 0.10000000149011612);
|
|
assert(Math.hypot(), 0);
|
|
assert(Math.hypot(-2), 2);
|
|
assert(Math.hypot(3, 4), 5);
|
|
assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15);
|
|
}
|
|
|
|
function test_number()
|
|
{
|
|
assert(parseInt("123"), 123);
|
|
assert(parseInt(" 123r"), 123);
|
|
assert(parseInt("0x123"), 0x123);
|
|
assert(parseInt("0o123"), 0);
|
|
assert(+" 123 ", 123);
|
|
assert(+"0b111", 7);
|
|
assert(+"0o123", 83);
|
|
assert(parseFloat("2147483647"), 2147483647);
|
|
assert(parseFloat("2147483648"), 2147483648);
|
|
assert(parseFloat("-2147483647"), -2147483647);
|
|
assert(parseFloat("-2147483648"), -2147483648);
|
|
assert(parseFloat("0x1234"), 0);
|
|
assert(parseFloat("Infinity"), Infinity);
|
|
assert(parseFloat("-Infinity"), -Infinity);
|
|
assert(parseFloat("123.2"), 123.2);
|
|
assert(parseFloat("123.2e3"), 123200);
|
|
assert(Number.isNaN(Number("+")));
|
|
assert(Number.isNaN(Number("-")));
|
|
assert(Number.isNaN(Number("\x00a")));
|
|
|
|
// TODO: Fix rounding errors on Windows/Cygwin.
|
|
if (typeof os !== 'undefined' && ['win32', 'cygwin'].includes(os.platform)) {
|
|
return;
|
|
}
|
|
|
|
assert((25).toExponential(0), "3e+1");
|
|
assert((-25).toExponential(0), "-3e+1");
|
|
assert((2.5).toPrecision(1), "3");
|
|
assert((-2.5).toPrecision(1), "-3");
|
|
assert((1.125).toFixed(2), "1.13");
|
|
assert((-1.125).toFixed(2), "-1.13");
|
|
}
|
|
|
|
function test_eval2()
|
|
{
|
|
var g_call_count = 0;
|
|
/* force non strict mode for f1 and f2 */
|
|
var f1 = new Function("eval", "eval(1, 2)");
|
|
var f2 = new Function("eval", "eval(...[1, 2])");
|
|
function g(a, b) {
|
|
assert(a, 1);
|
|
assert(b, 2);
|
|
g_call_count++;
|
|
}
|
|
f1(g);
|
|
f2(g);
|
|
assert(g_call_count, 2);
|
|
}
|
|
|
|
function test_eval()
|
|
{
|
|
function f(b) {
|
|
var x = 1;
|
|
return eval(b);
|
|
}
|
|
var r, a;
|
|
|
|
r = eval("1+1;");
|
|
assert(r, 2, "eval");
|
|
|
|
r = eval("var my_var=2; my_var;");
|
|
assert(r, 2, "eval");
|
|
assert(typeof my_var, "undefined");
|
|
|
|
assert(eval("if (1) 2; else 3;"), 2);
|
|
assert(eval("if (0) 2; else 3;"), 3);
|
|
|
|
assert(f.call(1, "this"), 1);
|
|
|
|
a = 2;
|
|
assert(eval("a"), 2);
|
|
|
|
eval("a = 3");
|
|
assert(a, 3);
|
|
|
|
assert(f("arguments.length", 1), 2);
|
|
assert(f("arguments[1]", 1), 1);
|
|
|
|
a = 4;
|
|
assert(f("a"), 4);
|
|
f("a=3");
|
|
assert(a, 3);
|
|
|
|
test_eval2();
|
|
}
|
|
|
|
function test_typed_array()
|
|
{
|
|
var buffer, a, i, str;
|
|
|
|
a = new Uint8Array(4);
|
|
assert(a.length, 4);
|
|
for(i = 0; i < a.length; i++)
|
|
a[i] = i;
|
|
assert(a.join(","), "0,1,2,3");
|
|
a[0] = -1;
|
|
assert(a[0], 255);
|
|
|
|
a = new Int8Array(3);
|
|
a[0] = 255;
|
|
assert(a[0], -1);
|
|
|
|
a = new Int32Array(3);
|
|
a[0] = Math.pow(2, 32) - 1;
|
|
assert(a[0], -1);
|
|
assert(a.BYTES_PER_ELEMENT, 4);
|
|
|
|
a = new Uint8ClampedArray(4);
|
|
a[0] = -100;
|
|
a[1] = 1.5;
|
|
a[2] = 0.5;
|
|
a[3] = 1233.5;
|
|
assert(a.toString(), "0,2,0,255");
|
|
|
|
buffer = new ArrayBuffer(16);
|
|
assert(buffer.byteLength, 16);
|
|
a = new Uint32Array(buffer, 12, 1);
|
|
assert(a.length, 1);
|
|
a[0] = -1;
|
|
|
|
a = new Uint16Array(buffer, 2);
|
|
a[0] = -1;
|
|
|
|
a = new Float32Array(buffer, 8, 1);
|
|
a[0] = 1;
|
|
|
|
a = new Uint8Array(buffer);
|
|
|
|
str = a.toString();
|
|
/* test little and big endian cases */
|
|
if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" &&
|
|
str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") {
|
|
assert(false);
|
|
}
|
|
|
|
assert(a.buffer, buffer);
|
|
|
|
a = new Uint8Array([1, 2, 3, 4]);
|
|
assert(a.toString(), "1,2,3,4");
|
|
a.set([10, 11], 2);
|
|
assert(a.toString(), "1,2,10,11");
|
|
}
|
|
|
|
function test_json()
|
|
{
|
|
var a, s;
|
|
s = '{"x":1,"y":true,"z":null,"a":[1,2,3],"s":"str"}';
|
|
a = JSON.parse(s);
|
|
assert(a.x, 1);
|
|
assert(a.y, true);
|
|
assert(a.z, null);
|
|
assert(JSON.stringify(a), s);
|
|
|
|
/* indentation test */
|
|
assert(JSON.stringify([[{x:1,y:{},z:[]},2,3]],undefined,1),
|
|
`[
|
|
[
|
|
{
|
|
"x": 1,
|
|
"y": {},
|
|
"z": []
|
|
},
|
|
2,
|
|
3
|
|
]
|
|
]`);
|
|
}
|
|
|
|
function test_date()
|
|
{
|
|
// Date Time String format is YYYY-MM-DDTHH:mm:ss.sssZ
|
|
// accepted date formats are: YYYY, YYYY-MM and YYYY-MM-DD
|
|
// accepted time formats are: THH:mm, THH:mm:ss, THH:mm:ss.sss
|
|
// expanded years are represented with 6 digits prefixed by + or -
|
|
// -000000 is invalid.
|
|
// A string containing out-of-bounds or nonconforming elements
|
|
// is not a valid instance of this format.
|
|
// Hence the fractional part after . should have 3 digits and how
|
|
// a different number of digits is handled is implementation defined.
|
|
assert(Date.parse(""), NaN);
|
|
assert(Date.parse("2000"), 946684800000);
|
|
assert(Date.parse("2000-01"), 946684800000);
|
|
assert(Date.parse("2000-01-01"), 946684800000);
|
|
//assert(Date.parse("2000-01-01T"), NaN);
|
|
//assert(Date.parse("2000-01-01T00Z"), NaN);
|
|
assert(Date.parse("2000-01-01T00:00Z"), 946684800000);
|
|
assert(Date.parse("2000-01-01T00:00:00Z"), 946684800000);
|
|
assert(Date.parse("2000-01-01T00:00:00.1Z"), 946684800100);
|
|
assert(Date.parse("2000-01-01T00:00:00.10Z"), 946684800100);
|
|
assert(Date.parse("2000-01-01T00:00:00.100Z"), 946684800100);
|
|
assert(Date.parse("2000-01-01T00:00:00.1000Z"), 946684800100);
|
|
assert(Date.parse("2000-01-01T00:00:00+00:00"), 946684800000);
|
|
//assert(Date.parse("2000-01-01T00:00:00+00:30"), 946686600000);
|
|
var d = new Date("2000T00:00"); // Jan 1st 2000, 0:00:00 local time
|
|
assert(typeof d === 'object' && d.toString() != 'Invalid Date');
|
|
assert((new Date('Jan 1 2000')).toISOString(),
|
|
d.toISOString());
|
|
assert((new Date('Jan 1 2000 00:00')).toISOString(),
|
|
d.toISOString());
|
|
assert((new Date('Jan 1 2000 00:00:00')).toISOString(),
|
|
d.toISOString());
|
|
assert((new Date('Jan 1 2000 00:00:00 GMT+0100')).toISOString(),
|
|
'1999-12-31T23:00:00.000Z');
|
|
assert((new Date('Jan 1 2000 00:00:00 GMT+0200')).toISOString(),
|
|
'1999-12-31T22:00:00.000Z');
|
|
assert((new Date('Sat Jan 1 2000')).toISOString(),
|
|
d.toISOString());
|
|
assert((new Date('Sat Jan 1 2000 00:00')).toISOString(),
|
|
d.toISOString());
|
|
assert((new Date('Sat Jan 1 2000 00:00:00')).toISOString(),
|
|
d.toISOString());
|
|
assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0100')).toISOString(),
|
|
'1999-12-31T23:00:00.000Z');
|
|
assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0200')).toISOString(),
|
|
'1999-12-31T22:00:00.000Z');
|
|
|
|
var d = new Date(1506098258091);
|
|
assert(d.toISOString(), "2017-09-22T16:37:38.091Z");
|
|
d.setUTCHours(18, 10, 11);
|
|
assert(d.toISOString(), "2017-09-22T18:10:11.091Z");
|
|
var a = Date.parse(d.toISOString());
|
|
assert((new Date(a)).toISOString(), d.toISOString());
|
|
|
|
assert((new Date("2020-01-01T01:01:01.123Z")).toISOString(),
|
|
"2020-01-01T01:01:01.123Z");
|
|
/* implementation defined behavior */
|
|
assert((new Date("2020-01-01T01:01:01.1Z")).toISOString(),
|
|
"2020-01-01T01:01:01.100Z");
|
|
assert((new Date("2020-01-01T01:01:01.12Z")).toISOString(),
|
|
"2020-01-01T01:01:01.120Z");
|
|
assert((new Date("2020-01-01T01:01:01.1234Z")).toISOString(),
|
|
"2020-01-01T01:01:01.123Z");
|
|
assert((new Date("2020-01-01T01:01:01.12345Z")).toISOString(),
|
|
"2020-01-01T01:01:01.123Z");
|
|
assert((new Date("2020-01-01T01:01:01.1235Z")).toISOString(),
|
|
"2020-01-01T01:01:01.123Z");
|
|
assert((new Date("2020-01-01T01:01:01.9999Z")).toISOString(),
|
|
"2020-01-01T01:01:01.999Z");
|
|
|
|
assert(Date.UTC(2017), 1483228800000);
|
|
assert(Date.UTC(2017, 9), 1506816000000);
|
|
assert(Date.UTC(2017, 9, 22), 1508630400000);
|
|
assert(Date.UTC(2017, 9, 22, 18), 1508695200000);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10), 1508695800000);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10, 11), 1508695811000);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91), 1508695811091);
|
|
|
|
assert(Date.UTC(NaN), NaN);
|
|
assert(Date.UTC(2017, NaN), NaN);
|
|
assert(Date.UTC(2017, 9, NaN), NaN);
|
|
assert(Date.UTC(2017, 9, 22, NaN), NaN);
|
|
assert(Date.UTC(2017, 9, 22, 18, NaN), NaN);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10, NaN), NaN);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10, 11, NaN), NaN);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91, NaN), 1508695811091);
|
|
|
|
// TODO: Fix rounding errors on Windows/Cygwin.
|
|
if (!(typeof os !== 'undefined' && ['win32', 'cygwin'].includes(os.platform))) {
|
|
// from test262/test/built-ins/Date/UTC/fp-evaluation-order.js
|
|
assert(Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740), 29312,
|
|
'order of operations / precision in MakeTime');
|
|
assert(Date.UTC(1970, 0, 213503982336, 0, 0, 0, -18446744073709552000), 34447360,
|
|
'precision in MakeDate');
|
|
}
|
|
//assert(Date.UTC(2017 - 1e9, 9 + 12e9), 1506816000000); // node fails this
|
|
assert(Date.UTC(2017, 9, 22 - 1e10, 18 + 24e10), 1508695200000);
|
|
assert(Date.UTC(2017, 9, 22, 18 - 1e10, 10 + 60e10), 1508695800000);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10 - 1e10, 11 + 60e10), 1508695811000);
|
|
assert(Date.UTC(2017, 9, 22, 18, 10, 11 - 1e12, 91 + 1000e12), 1508695811091);
|
|
}
|
|
|
|
function test_regexp()
|
|
{
|
|
var a, str;
|
|
str = "abbbbbc";
|
|
a = /(b+)c/.exec(str);
|
|
assert(a[0], "bbbbbc");
|
|
assert(a[1], "bbbbb");
|
|
assert(a.index, 1);
|
|
assert(a.input, str);
|
|
a = /(b+)c/.test(str);
|
|
assert(a, true);
|
|
assert(/\x61/.exec("a")[0], "a");
|
|
assert(/\u0061/.exec("a")[0], "a");
|
|
assert(/\ca/.exec("\x01")[0], "\x01");
|
|
assert(/\\a/.exec("\\a")[0], "\\a");
|
|
assert(/\c0/.exec("\\c0")[0], "\\c0");
|
|
|
|
a = /(\.(?=com|org)|\/)/.exec("ah.com");
|
|
assert(a.index === 2 && a[0] === ".");
|
|
|
|
a = /(\.(?!com|org)|\/)/.exec("ah.com");
|
|
assert(a, null);
|
|
|
|
a = /(?=(a+))/.exec("baaabac");
|
|
assert(a.index === 1 && a[0] === "" && a[1] === "aaa");
|
|
|
|
a = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac");
|
|
assert(a, ["zaacbbbcac","z","ac","a",,"c"]);
|
|
|
|
a = eval("/\0a/");
|
|
assert(a.toString(), "/\0a/");
|
|
assert(a.exec("\0a")[0], "\0a");
|
|
|
|
assert(/{1a}/.toString(), "/{1a}/");
|
|
a = /a{1+/.exec("a{11");
|
|
assert(a, ["a{11"]);
|
|
|
|
/* test zero length matches */
|
|
a = /(?:(?=(abc)))a/.exec("abc");
|
|
assert(a, ["a", "abc"]);
|
|
a = /(?:(?=(abc)))?a/.exec("abc");
|
|
assert(a, ["a", undefined]);
|
|
a = /(?:(?=(abc))){0,2}a/.exec("abc");
|
|
assert(a, ["a", undefined]);
|
|
a = /(?:|[\w])+([0-9])/.exec("123a23");
|
|
assert(a, ["123a23", "3"]);
|
|
a = /()*?a/.exec(",");
|
|
assert(a, null);
|
|
}
|
|
|
|
function test_symbol()
|
|
{
|
|
var a, b, obj, c;
|
|
a = Symbol("abc");
|
|
obj = {};
|
|
obj[a] = 2;
|
|
assert(obj[a], 2);
|
|
assert(typeof obj["abc"], "undefined");
|
|
assert(String(a), "Symbol(abc)");
|
|
b = Symbol("abc");
|
|
assert(a == a);
|
|
assert(a === a);
|
|
assert(a != b);
|
|
assert(a !== b);
|
|
|
|
b = Symbol.for("abc");
|
|
c = Symbol.for("abc");
|
|
assert(b === c);
|
|
assert(b !== a);
|
|
|
|
assert(Symbol.keyFor(b), "abc");
|
|
assert(Symbol.keyFor(a), undefined);
|
|
|
|
a = Symbol("aaa");
|
|
assert(a.valueOf(), a);
|
|
assert(a.toString(), "Symbol(aaa)");
|
|
|
|
b = Object(a);
|
|
assert(b.valueOf(), a);
|
|
assert(b.toString(), "Symbol(aaa)");
|
|
}
|
|
|
|
function test_map()
|
|
{
|
|
var a, i, n, tab, o, v;
|
|
n = 1000;
|
|
|
|
a = new Map();
|
|
for (var i = 0; i < n; i++) {
|
|
a.set(i, i);
|
|
}
|
|
a.set(-2147483648, 1);
|
|
assert(a.get(-2147483648), 1);
|
|
assert(a.get(-2147483647 - 1), 1);
|
|
assert(a.get(-2147483647.5 - 0.5), 1);
|
|
|
|
a.set(1n, 1n);
|
|
assert(a.get(1n), 1n);
|
|
assert(a.get(2n**1000n - (2n**1000n - 1n)), 1n);
|
|
|
|
a = new Map();
|
|
tab = [];
|
|
for(i = 0; i < n; i++) {
|
|
v = { };
|
|
o = { id: i };
|
|
tab[i] = [o, v];
|
|
a.set(o, v);
|
|
}
|
|
|
|
assert(a.size, n);
|
|
for(i = 0; i < n; i++) {
|
|
assert(a.get(tab[i][0]), tab[i][1]);
|
|
}
|
|
|
|
i = 0;
|
|
a.forEach(function (v, o) {
|
|
assert(o, tab[i++][0]);
|
|
assert(a.has(o));
|
|
assert(a.delete(o));
|
|
assert(!a.has(o));
|
|
});
|
|
|
|
assert(a.size, 0);
|
|
}
|
|
|
|
function test_weak_map()
|
|
{
|
|
var a, i, n, tab, o, v, n2;
|
|
a = new WeakMap();
|
|
n = 10;
|
|
tab = [];
|
|
for(i = 0; i < n; i++) {
|
|
v = { };
|
|
o = { id: i };
|
|
tab[i] = [o, v];
|
|
a.set(o, v);
|
|
}
|
|
o = null;
|
|
|
|
n2 = n >> 1;
|
|
for(i = 0; i < n2; i++) {
|
|
a.delete(tab[i][0]);
|
|
}
|
|
for(i = n2; i < n; i++) {
|
|
tab[i][0] = null; /* should remove the object from the WeakMap too */
|
|
}
|
|
/* the WeakMap should be empty here */
|
|
|
|
// test symbol as key
|
|
var symbol_key = Symbol("key");
|
|
a = new WeakMap();
|
|
a.set(symbol_key, "hello");
|
|
assert(a.has(symbol_key), true);
|
|
assert(a.get(symbol_key), "hello");
|
|
|
|
symbol_key = undefined;
|
|
assert(a.has(symbol_key), false);
|
|
assert(a.get(symbol_key), undefined);
|
|
}
|
|
|
|
function test_weak_ref()
|
|
{
|
|
var obj = {};
|
|
var ref = new WeakRef(obj);
|
|
var ref2 = new WeakRef(obj);
|
|
|
|
assert(ref.deref(), obj);
|
|
assert(ref2.deref(), obj);
|
|
|
|
obj = undefined;
|
|
/* weak ref should be released */
|
|
assert(ref.deref(), undefined);
|
|
assert(ref2.deref(), undefined);
|
|
|
|
// symbol
|
|
var sym = Symbol("sym")
|
|
var ref3 = new WeakRef(sym);
|
|
assert(ref3.deref(), sym);
|
|
new WeakRef(Symbol.hasInstance);
|
|
|
|
sym = undefined;
|
|
assert(ref3.deref(), undefined);
|
|
|
|
function should_fail(block) {
|
|
try {
|
|
block()
|
|
} catch (e) {
|
|
return
|
|
}
|
|
throw_error("weak ref should throw exception, but it not");
|
|
}
|
|
|
|
should_fail(() => new WeakRef("string"));
|
|
should_fail(() => new WeakRef(/* number */0));
|
|
should_fail(() => new WeakRef(/* registered symbol */ Symbol.for("test")));
|
|
|
|
/* cyclic ref */
|
|
obj = {};
|
|
ref = new WeakRef(obj);
|
|
obj["x"] = ref;
|
|
}
|
|
|
|
function test_generator()
|
|
{
|
|
function *f() {
|
|
var ret;
|
|
yield 1;
|
|
ret = yield 2;
|
|
assert(ret, "next_arg");
|
|
return 3;
|
|
}
|
|
function *f2() {
|
|
yield 1;
|
|
yield 2;
|
|
return "ret_val";
|
|
}
|
|
function *f1() {
|
|
var ret = yield *f2();
|
|
assert(ret, "ret_val");
|
|
return 3;
|
|
}
|
|
function *f3() {
|
|
var ret;
|
|
/* test stack consistency with nip_n to handle yield return +
|
|
* finally clause */
|
|
try {
|
|
ret = 2 + (yield 1);
|
|
} catch(e) {
|
|
} finally {
|
|
ret++;
|
|
}
|
|
return ret;
|
|
}
|
|
var g, v;
|
|
g = f();
|
|
v = g.next();
|
|
assert(v.value === 1 && v.done === false);
|
|
v = g.next();
|
|
assert(v.value === 2 && v.done === false);
|
|
v = g.next("next_arg");
|
|
assert(v.value === 3 && v.done === true);
|
|
v = g.next();
|
|
assert(v.value === undefined && v.done === true);
|
|
|
|
g = f1();
|
|
v = g.next();
|
|
assert(v.value === 1 && v.done === false);
|
|
v = g.next();
|
|
assert(v.value === 2 && v.done === false);
|
|
v = g.next();
|
|
assert(v.value === 3 && v.done === true);
|
|
v = g.next();
|
|
assert(v.value === undefined && v.done === true);
|
|
|
|
g = f3();
|
|
v = g.next();
|
|
assert(v.value === 1 && v.done === false);
|
|
v = g.next(3);
|
|
assert(v.value === 6 && v.done === true);
|
|
}
|
|
|
|
test();
|
|
test_function();
|
|
test_enum();
|
|
test_array();
|
|
test_string();
|
|
test_math();
|
|
test_number();
|
|
test_eval();
|
|
test_typed_array();
|
|
test_json();
|
|
test_date();
|
|
test_regexp();
|
|
test_symbol();
|
|
test_map();
|
|
test_weak_map();
|
|
test_weak_ref();
|
|
test_generator();
|