@deployport/specular-runtime
Version:
Runtime for Specular API clients with support for Node.js and Browser
283 lines (269 loc) • 9.99 kB
JavaScript
import test from 'tape';
import { SpecularPackage, ResponseMeta, BodyMeta, BodyType } from './generated-client/specular.js';
import {
Metadata,
} from '../lib/index.js';
import { StructPath } from '../lib/metadata/struct.js';
import { defaultZeroTime } from '../lib/metadata/builtin.js';
import { BlobToBase64 } from '../lib/runtime/builtin.js';
const _pkg = SpecularPackage();
test('StructPath', (t) => {
const sp = StructPath.fromString('application/spec.myns.mymod.mytype');
t.equal(sp.name, "mytype");
t.equal(sp.module.namespace, "myns");
t.equal(sp.module.name, "mymod");
t.end();
});
test('Deserialize with builtins props', (t) => {
t.test("missing", (t) => {
const obj = {
"body": {}
};
const s = _pkg.requireBuildFromJSON(ResponseMeta.path, obj);
t.notEqual(s.body, null);
t.equal(s.body.contentLengthInt32, 0);
t.equal(s.body.contentLengthInt64, 0);
t.equal(s.body.contentLengthFloat32, 0);
t.equal(s.body.contentLengthFloat64, 0);
t.equal(s.body.contentLengthFloat64Nullable, null);
t.equal(s.body.contentLengthUint32, 0);
t.equal(s.body.contentLengthUint64, 0);
t.equal(s.body.messageString, "");
t.equal(s.body.messageStringNullable, null);
t.deepEqual(s.body.createdAt, defaultZeroTime());
t.deepEqual(s.body.createdAtNullable, null);
t.notEqual(s.body.fileData, null);
t.equal(typeof s.body.fileData, 'object');
t.equal(s.body.fileData.constructor, Blob);
t.equal(s.body.fileDataNullable, null);
t.equal(s.body.bodyType, BodyType.Normal, "default enum value when missing");
t.equal(s.body.bodyTypeNullable, null);
t.end();
});
t.test("value", (t) => {
const obj = {
"body": {
"contentLengthInt32": 32,
"contentLengthFloat64Nullable": 64,
"messageString": "msg",
"messageStringNullable": "msg nullable",
"createdAtNullable": "2024-06-18T02:02:07.602Z",
"fileData": "",
"bodyType": "special",
"bodyTypeNullable": "special"
}
};
const s = _pkg.requireBuildFromJSON(ResponseMeta.path, obj);
t.notEqual(s.body, null);
t.equal(s.body.contentLengthInt32, 32);
t.equal(s.body.contentLengthFloat64Nullable, 64);
t.equal(s.body.messageString, "msg");
t.equal(s.body.messageStringNullable, "msg nullable");
t.same(s.body.createdAtNullable, new Date('2024-06-18T02:02:07.602Z'));
t.same(s.body.fileData, new Blob([]));
t.equal(s.body.bodyType, BodyType.Special);
t.equal(s.body.bodyTypeNullable, BodyType.Special);
t.end();
});
t.test("value binary", async (t) => {
const obj = {
"body": {
"fileData": await BlobToBase64(new Blob(['hi'], { type: "text/plain" })),
}
};
const s = _pkg.requireBuildFromJSON(ResponseMeta.path, obj);
t.notEqual(s.body, null);
t.notEqual(s.body.fileData, null);
t.true(areArrayBuffersEqual(await s.body.fileData.arrayBuffer(), await new Blob(['hi'], { type: "text/plain" }).arrayBuffer()));
t.end();
});
t.test("nullable binary null", async (t) => {
const obj = {
"body": {
"fileDataNullable": null,
}
};
const s = _pkg.requireBuildFromJSON(ResponseMeta.path, obj);
t.notEqual(s.body, null);
t.equal(s.body.fileDataNullable, null);
t.end();
});
t.test("nullable binary value", async (t) => {
const obj = {
"body": {
"fileDataNullable": await BlobToBase64(new Blob(['hi'], { type: "text/plain" })),
}
};
const s = _pkg.requireBuildFromJSON(ResponseMeta.path, obj);
t.notEqual(s.body, null);
t.notEqual(s.body.fileDataNullable, null);
t.true(areArrayBuffersEqual(await s.body.fileDataNullable.arrayBuffer(), await new Blob(['hi'], { type: "text/plain" }).arrayBuffer()));
t.end();
});
});
function areArrayBuffersEqual(buffer1, buffer2) {
if (buffer1.byteLength !== buffer2.byteLength) return false;
const view1 = new Uint8Array(buffer1);
const view2 = new Uint8Array(buffer2);
for (let i = 0; i < view1.length; i++) {
if (view1[i] !== view2[i]) return false;
}
return true;
}
test('Deserialize with struct props', (t) => {
t.test("null field", (t) => {
const obj = {
"body": null
};
const s = _pkg.requireBuildFromJSON(ResponseMeta.path, obj);
t.equal(s.body, null);
t.end();
});
t.test("missing field", (t) => {
const obj = {};
const s = _pkg.requireBuildFromJSON(ResponseMeta.path, obj);
console.log("s", s)
t.equal(s.body, null);
t.end();
});
});
test('Serialize with struct props', (t) => {
t.test("missing", async (t) => {
const obj = await ResponseMeta.serialize({})
t.deepEqual(Object.keys(obj), [])
t.end()
});
t.test("struct prop null", async (t) => {
const obj = await ResponseMeta.serialize({
body: null
})
t.deepEqual(Object.keys(obj), [])
t.end()
});
t.test("struct prop empty", async (t) => {
const obj = await ResponseMeta.serialize({
body: {}
})
t.false(Object.keys(obj).indexOf('body'), -1)
t.end()
});
});
test('Serialize with builtin props', (t) => {
t.test("missing", async (t) => {
const obj = await BodyMeta.serialize({})
t.deepEqual(Object.keys(obj), [])
t.end()
});
t.test("custom value", async (t) => {
const obj = await BodyMeta.serialize({
contentLengthInt32: 32,
contentLengthUint64Nullable: 64,
messageString: 'msg',
})
const props = Object.keys(obj);
t.true(props.includes('contentLengthInt32'))
t.false(props.includes('contentLengthFloat64Nullable'), 'should not include default nullable null')
t.equal(obj.contentLengthInt32, 32);
t.equal(obj.contentLengthUint64Nullable, 64);
t.equal(obj.messageString, 'msg');
t.end()
});
t.test("nulls", async (t) => {
const obj = await BodyMeta.serialize({
messageStringNullable: null,
contentLengthFloat64Nullable: null,
fileDataNullable: null,
bodyTypeNullable: null,
})
const props = Object.keys(obj);
t.false(props.includes('messageStringNullable'))
t.false(props.includes('contentLengthFloat64Nullable'), 'should not include default nullable null')
t.false(props.includes('fileDataNullable'), 'should not include default nullable null')
t.false(props.includes('bodyTypeNullable'), 'should not include default nullable null')
t.end()
});
t.test("nullable set", async (t) => {
const obj = await BodyMeta.serialize({
messageStringNullable: 'val',
bodyTypeNullable: 'special',
})
const props = Object.keys(obj);
t.true(props.includes('messageStringNullable'))
t.equal(obj.messageStringNullable, 'val')
t.equal(obj.bodyTypeNullable, 'special')
t.end()
});
t.test("time default", async (t) => {
const obj = await BodyMeta.serialize({
createdAt: defaultZeroTime(),
})
const props = Object.keys(obj);
t.false(props.includes('createdAt'), 'should not include date since is default date zero value')
t.deepEqual(props, []);
t.end()
});
t.test("time custom", async (t) => {
const obj = await BodyMeta.serialize({
createdAt: new Date(Date.UTC(2024, 1, 1)),
})
const props = Object.keys(obj);
t.true(props.includes('createdAt'))
t.deepEqual(props, ['createdAt']);
t.equal(obj.createdAt, '2024-02-01T00:00:00.000Z');
t.end()
});
t.test("binary default", async (t) => {
const obj = await BodyMeta.serialize({
fileData: new Blob([''], { type: "text/plain" }),
})
const props = Object.keys(obj);
t.false(props.includes('fileData'), 'should not include date since is default binary is an empty string')
t.deepEqual(props, []);
t.end()
});
t.test("binary value", async (t) => {
const obj = await BodyMeta.serialize({
fileData: new Blob(['hi'], { type: "text/plain" }),
fileDataNullable: new Blob(['hi'], { type: "text/plain" }),
})
const props = Object.keys(obj);
t.true(props.includes('fileData'))
t.equal(obj.fileData, 'aGk=');
t.equal(obj.fileDataNullable, 'aGk=');
t.end()
});
t.test("enum default", async (t) => {
const obj = await BodyMeta.serialize({
bodyType: BodyType.Normal,
})
const props = Object.keys(obj);
t.false(props.includes('bodyType'), 'should not include since default value was set')
t.deepEqual(props, []);
t.end()
});
});
const importingPkg = new Metadata.Package(
'specularJS', 'importing',
);
importingPkg.importPackage(_pkg);
export const ImportingDoc = new Metadata.Struct(
importingPkg,
"Doc",
);
test('imported instantiation', (t) => {
const obj = {
"body": null
};
const s = importingPkg.requireBuildFromJSON(ResponseMeta.path, obj);
t.equal(s.body, null);
t.end();
});
test('unmatched case instantiation', (t) => {
const obj = {
"body": null
};
const sp = StructPath.fromString(ResponseMeta.path.mediaType.toUpperCase());
const s = _pkg.requireBuildFromJSON(sp, obj);
t.equal(s.body, null);
t.end();
});