46 lines
2.9 KiB
JavaScript
46 lines
2.9 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { bindQxHandler, decodeQxValue, encodeQxValue, jsToProtoValue, liveValue, protoValueToJs } from "../dist/index.js";
|
|
const scalar = (name) => ({ kind: "scalar", name });
|
|
const unit = { kind: "builtin", name: "unit" };
|
|
test("binding codecs round trip nested bytes, 64-bit integers, nulls, and references", () => {
|
|
const values = [[scalar("int64"), -(2n ** 63n)], [scalar("uint64"), 2n ** 64n - 1n],
|
|
[scalar("bytes"), new Uint8Array([0, 255])],
|
|
[{ kind: "list", value: { kind: "optional", value: scalar("int64") } }, [null, 2n ** 60n]],
|
|
[{ kind: "object-ref", expectation: { kind: "atom", atomId: "thing" } }, "obj:thing"]];
|
|
for (const [type, value] of values) assert.deepEqual(decodeQxValue(type, encodeQxValue(type, value, {}), {}), value);
|
|
});
|
|
test("typed state and interface ports preserve declared values and exact operation IDs", async () => {
|
|
const spec = { inputType: scalar("int64"), outputType: scalar("bytes"), ports: {
|
|
data: { kind: "state", id: "state-id", valueType: scalar("int64"), primitives: ["read", "write"] },
|
|
reader: { kind: "interface", id: "interface-id", operations: { "payload.get": { id: "get-id", inputType: unit, outputType: scalar("bytes") } } },
|
|
} };
|
|
let written;
|
|
const handler = bindQxHandler(spec, async ({ input, ports }) => {
|
|
assert.equal(input, 2n ** 60n);
|
|
assert.equal(await ports.data.get(), 9n);
|
|
await ports.data.set(input);
|
|
return ports.reader["payload.get"]();
|
|
}, {});
|
|
const result = await handler({ inputProto: { value: jsToProtoValue(2n ** 60n) }, objectId: "obj",
|
|
state: (id) => { assert.equal(id, "state-id"); return {
|
|
live: async () => liveValue(jsToProtoValue(9n)), set: async (value) => { written = value; },
|
|
}; },
|
|
interface: (id) => { assert.equal(id, "interface-id"); return { live: async (operation, input) => {
|
|
assert.equal(operation, "get-id"); assert.deepEqual(input, {}); return liveValue(jsToProtoValue(new Uint8Array([7])));
|
|
} }; },
|
|
});
|
|
assert.equal(written.$quixosValue.kind.value, String(2n ** 60n));
|
|
assert.deepEqual(result.$quixosValue.kind.value, new Uint8Array([7]));
|
|
});
|
|
test("external message bindings and derived event types are used at the boundary", async () => {
|
|
const message = { kind: "message", descriptorId: "Payload" };
|
|
const messages = { Payload: { encode: jsToProtoValue, decode: protoValueToJs } };
|
|
const handler = bindQxHandler({ inputType: message, outputType: { kind: "builtin", name: "watch-handle" }, eventType: message, ports: {} },
|
|
{ kind: "derived", get: ({ input }) => ({ value: input.title }) }, messages);
|
|
assert.equal(handler.kind, "derived");
|
|
const result = await handler.get({ objectId: "obj", inputProto: { title: jsToProtoValue("hello") } });
|
|
assert.deepEqual(protoValueToJs(result.$quixosValue), { value: "hello" });
|
|
assert.throws(() => encodeQxValue(message, {}, {}), /Missing message binding/);
|
|
});
|