Checkpoint before integration and package validation. Assisted-by: SurmAgent:unknown [read] [edit] [bash]
338 lines
9.1 KiB
JavaScript
338 lines
9.1 KiB
JavaScript
import * as std from "qjs:std";
|
|
import * as bjson from "qjs:bjson";
|
|
import { assert, assertArrayEquals } from "./assert.js";
|
|
|
|
function isArrayLike(a)
|
|
{
|
|
return Array.isArray(a) ||
|
|
(a instanceof Uint8ClampedArray) ||
|
|
(a instanceof Uint8Array) ||
|
|
(a instanceof Uint16Array) ||
|
|
(a instanceof Uint32Array) ||
|
|
(a instanceof Int8Array) ||
|
|
(a instanceof Int16Array) ||
|
|
(a instanceof Int32Array) ||
|
|
(a instanceof Float16Array) ||
|
|
(a instanceof Float32Array) ||
|
|
(a instanceof Float64Array);
|
|
}
|
|
|
|
function toStr(a)
|
|
{
|
|
var s, i, props, prop;
|
|
|
|
switch(typeof(a)) {
|
|
case "object":
|
|
if (a === null)
|
|
return "null";
|
|
if (a instanceof Date) {
|
|
s = "Date(" + toStr(a.valueOf()) + ")";
|
|
} else if (a instanceof Number) {
|
|
s = "Number(" + toStr(a.valueOf()) + ")";
|
|
} else if (a instanceof String) {
|
|
s = "String(" + toStr(a.valueOf()) + ")";
|
|
} else if (a instanceof Boolean) {
|
|
s = "Boolean(" + toStr(a.valueOf()) + ")";
|
|
} else if (isArrayLike(a)) {
|
|
s = "[";
|
|
for(i = 0; i < a.length; i++) {
|
|
if (i != 0)
|
|
s += ",";
|
|
s += toStr(a[i]);
|
|
}
|
|
s += "]";
|
|
} else {
|
|
props = Object.keys(a);
|
|
s = "{";
|
|
for(i = 0; i < props.length; i++) {
|
|
if (i != 0)
|
|
s += ",";
|
|
prop = props[i];
|
|
s += prop + ":" + toStr(a[prop]);
|
|
}
|
|
s += "}";
|
|
}
|
|
return s;
|
|
case "undefined":
|
|
return "undefined";
|
|
case "string":
|
|
return JSON.stringify(a);
|
|
case "number":
|
|
if (a == 0 && 1 / a < 0)
|
|
return "-0";
|
|
else
|
|
return a.toString();
|
|
break;
|
|
default:
|
|
return a.toString();
|
|
}
|
|
}
|
|
|
|
function bjson_test(a)
|
|
{
|
|
var buf, r, a_str, r_str;
|
|
a_str = toStr(a);
|
|
buf = bjson.write(a);
|
|
if (0) {
|
|
print(a_str, "->", new Uint8Array(buf).toHex());
|
|
}
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
r_str = toStr(r);
|
|
if (a_str != r_str) {
|
|
print(a_str);
|
|
print(r_str);
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
function bjson_test_arraybuffer()
|
|
{
|
|
var buf, array_buffer;
|
|
|
|
array_buffer = new ArrayBuffer(4);
|
|
assert(array_buffer.byteLength, 4);
|
|
assert(array_buffer.maxByteLength, 4);
|
|
assert(array_buffer.resizable, false);
|
|
buf = bjson.write(array_buffer);
|
|
array_buffer = bjson.read(buf, 0, buf.byteLength);
|
|
assert(array_buffer.byteLength, 4);
|
|
assert(array_buffer.maxByteLength, 4);
|
|
assert(array_buffer.resizable, false);
|
|
|
|
array_buffer = new ArrayBuffer(4, {maxByteLength: 4});
|
|
assert(array_buffer.byteLength, 4);
|
|
assert(array_buffer.maxByteLength, 4);
|
|
assert(array_buffer.resizable, true);
|
|
buf = bjson.write(array_buffer);
|
|
array_buffer = bjson.read(buf, 0, buf.byteLength);
|
|
assert(array_buffer.byteLength, 4);
|
|
assert(array_buffer.maxByteLength, 4);
|
|
assert(array_buffer.resizable, true);
|
|
|
|
array_buffer = new ArrayBuffer(4, {maxByteLength: 8});
|
|
assert(array_buffer.byteLength, 4);
|
|
assert(array_buffer.maxByteLength, 8);
|
|
assert(array_buffer.resizable, true);
|
|
buf = bjson.write(array_buffer);
|
|
array_buffer = bjson.read(buf, 0, buf.byteLength);
|
|
assert(array_buffer.byteLength, 4);
|
|
assert(array_buffer.maxByteLength, 8);
|
|
assert(array_buffer.resizable, true);
|
|
}
|
|
|
|
/* test multiple references to an object including circular
|
|
references */
|
|
function bjson_test_reference()
|
|
{
|
|
var array, buf, i, n, array_buffer;
|
|
n = 16;
|
|
array = [];
|
|
for(i = 0; i < n; i++)
|
|
array[i] = {};
|
|
array_buffer = new ArrayBuffer(n);
|
|
for(i = 0; i < n; i++) {
|
|
array[i].next = array[(i + 1) % n];
|
|
array[i].idx = i;
|
|
array[i].typed_array = new Uint8Array(array_buffer, i, 1);
|
|
}
|
|
buf = bjson.write(array, bjson.WRITE_OBJ_REFERENCE);
|
|
|
|
array = bjson.read(buf, 0, buf.byteLength, bjson.READ_OBJ_REFERENCE);
|
|
|
|
/* check the result */
|
|
for(i = 0; i < n; i++) {
|
|
assert(array[i].next, array[(i + 1) % n]);
|
|
assert(array[i].idx, i);
|
|
assert(array[i].typed_array.buffer, array_buffer);
|
|
assert(array[i].typed_array.length, 1);
|
|
assert(array[i].typed_array.byteOffset, i);
|
|
}
|
|
}
|
|
|
|
function bjson_test_regexp()
|
|
{
|
|
var buf, r;
|
|
|
|
bjson_test(/xyzzy/);
|
|
bjson_test(/xyzzy/digu);
|
|
|
|
buf = bjson.write(/(?<𝓓𝓸𝓰>dog)/);
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
assert("sup dog".match(r).groups["𝓓𝓸𝓰"], "dog");
|
|
}
|
|
|
|
function bjson_test_map()
|
|
{
|
|
var buf, r, xs;
|
|
|
|
xs = [["key", "value"]];
|
|
buf = bjson.write(new Map(xs));
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
assert(r instanceof Map);
|
|
assert([...r].toString(), xs.toString());
|
|
}
|
|
|
|
function bjson_test_set()
|
|
{
|
|
var buf, r, xs;
|
|
|
|
xs = ["one", "two", "three"];
|
|
buf = bjson.write(new Set(xs));
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
assert(r instanceof Set);
|
|
assert([...r].toString(), xs.toString());
|
|
}
|
|
|
|
function bjson_test_symbol()
|
|
{
|
|
var buf, r, o;
|
|
|
|
o = {[Symbol.toStringTag]: "42"};
|
|
buf = bjson.write(o);
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
assert(o.toString(), r.toString());
|
|
|
|
o = Symbol('foo');
|
|
buf = bjson.write(o);
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
assert(o.toString(), r.toString());
|
|
assert(o !== r);
|
|
|
|
o = Symbol.for('foo');
|
|
buf = bjson.write(o);
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
assert(o, r);
|
|
|
|
o = Symbol.toStringTag;
|
|
buf = bjson.write(o);
|
|
r = bjson.read(buf, 0, buf.byteLength);
|
|
assert(o, r);
|
|
}
|
|
|
|
function bjson_test_bytecode()
|
|
{
|
|
var buf, o, r, e, i;
|
|
|
|
o = std.evalScript(";(function f(o){ return o.i })", {compile_only: true});
|
|
buf = bjson.write(o, bjson.WRITE_OBJ_BYTECODE);
|
|
try {
|
|
bjson.read(buf, 0, buf.byteLength);
|
|
} catch (_e) {
|
|
e = _e;
|
|
}
|
|
assert(String(e), "SyntaxError: no bytecode allowed");
|
|
|
|
o = bjson.read(buf, 0, buf.byteLength, bjson.READ_OBJ_BYTECODE);
|
|
assert(String(o), "[function bytecode]");
|
|
o = std.evalScript(o, {eval_function: true});
|
|
for (i = 0; i < 42; i++) o({i}); // exercise o.i IC
|
|
}
|
|
|
|
function bjson_test_fuzz()
|
|
{
|
|
var corpus = [
|
|
["HP////8QAAAAAARg"],
|
|
["HP/////m5uaCLQ=="],
|
|
["HP////8AEQATBgYGBgYGBgYGBgb/////EAARAC8R/78vEf+/"],
|
|
["HP////8ACH8ACv////9//////////////////////////////9//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAA+fn5+fn5+fn5+fn5AAAAAAAGAKs="],
|
|
["HP////8ADgAAABQA", bjson.READ_OBJ_REFERENCE],
|
|
];
|
|
for (var [input, flags] of corpus) {
|
|
var buf = Uint8Array.fromBase64(input);
|
|
try {
|
|
bjson.read(buf, 0, buf.byteLength, flags);
|
|
} catch (e) {
|
|
if (/invalid version/.test(e.message)) throw e; // corpus needs update
|
|
if (/checksum error/.test(e.message)) throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
function bjson_test_csum()
|
|
{
|
|
var buf = bjson.write("fortytwo");
|
|
var tab = new Uint8Array(buf);
|
|
for (var i = 5; i < tab.length; i++) {
|
|
for (var k = 0; k < 256; k++) {
|
|
var t = tab[i];
|
|
if (t == k)
|
|
continue;
|
|
tab[i] = k;
|
|
var caught = false;
|
|
try {
|
|
bjson.read(buf, 0, buf.byteLength);
|
|
} catch (e) {
|
|
caught = /checksum error/.test(e.message);
|
|
}
|
|
assert(caught);
|
|
tab[i] = t;
|
|
}
|
|
}
|
|
}
|
|
|
|
function bjson_test_truncated_bigint()
|
|
{
|
|
var buf = bjson.write(-(2n ** 100n));
|
|
new DataView(buf).setUint32(1, 0xFFFFFFFF, true); // disable checksum
|
|
for (var n = 1; n < buf.byteLength; n++) {
|
|
var caught = false;
|
|
try {
|
|
bjson.read(buf, 0, n);
|
|
} catch (e) {
|
|
caught = /read after the end of the buffer/.test(e.message);
|
|
}
|
|
assert(caught);
|
|
}
|
|
}
|
|
|
|
function bjson_test_atom()
|
|
{
|
|
var o = {return:1, with:2, Map:3}; // Map tests LEB128 encoding
|
|
var b = bjson.write(o);
|
|
var r = bjson.read(b, 0, b.byteLength);
|
|
assertArrayEquals(Object.entries(o), Object.entries(r));
|
|
}
|
|
|
|
function bjson_test_all()
|
|
{
|
|
var obj;
|
|
|
|
bjson_test({x:1, y:2, if:3});
|
|
bjson_test([1, 2, 3]);
|
|
bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]);
|
|
if (typeof BigInt !== "undefined") {
|
|
bjson_test([BigInt("1"), -BigInt("0x123456789"),
|
|
BigInt("0x123456789abcdef123456789abcdef")]);
|
|
}
|
|
|
|
bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
|
|
|
|
bjson_test(new Int32Array([123123, 222111, -32222]));
|
|
bjson_test(new Float16Array([1024, 1024.5]));
|
|
bjson_test(new Float64Array([123123, 222111.5]));
|
|
|
|
/* tested with a circular reference */
|
|
obj = {};
|
|
obj.x = obj;
|
|
try {
|
|
bjson.write(obj);
|
|
assert(false);
|
|
} catch(e) {
|
|
assert(e instanceof TypeError);
|
|
}
|
|
|
|
bjson_test_arraybuffer();
|
|
bjson_test_reference();
|
|
bjson_test_regexp();
|
|
bjson_test_map();
|
|
bjson_test_set();
|
|
bjson_test_symbol();
|
|
bjson_test_bytecode();
|
|
bjson_test_fuzz();
|
|
bjson_test_csum();
|
|
bjson_test_atom();
|
|
bjson_test_truncated_bigint();
|
|
}
|
|
|
|
bjson_test_all();
|