import {expect, test} from 'vitest'; import Schema from './schema.js'; test('defaults values', () => { const compare = (specification, value) => { expect(new Schema(specification).defaultValue()) .to.deep.equal(value); }; [ 'uint8', 'int8', 'uint16', 'int16', 'uint32', 'int32', 'float32', 'float64', ].forEach((type) => { compare({type}, 0); }); [ 'uint64', 'int64', ].forEach((type) => { compare({type}, 0n); }); compare({type: 'string'}, ''); compare({type: 'array', subtype: {type: 'string'}}, []); compare( { type: 'object', properties: { foo: {type: 'uint8'}, bar: {type: 'string'}, baz: {type: 'object', properties: {blah: {type: 'array', subtype: {type: 'string'}}}}, }, }, {foo: 0, bar: '', baz: {blah: []}}, ); compare( { type: 'map', value: { type: 'object', properties: { foo: {type: 'uint8'}, bar: {type: 'string'}, baz: {type: 'object', properties: {blah: {type: 'array', subtype: {type: 'string'}}}}, }, }, }, {}, ); }); test('validates a schema', () => { [ 'uint8', 'int8', 'uint16', 'int16', 'uint32', 'int32', 'uint64', 'int64', 'float32', 'float64', 'string', ].forEach((type) => { expect(() => { new Schema({type}); new Schema({type: 'array', subtype: {type}}); new Schema({type: 'object', properties: {foo: {type}}}); new Schema({type: 'map', value: {type}}); }) .to.not.throw(); }); }); test('calculates the size of concrete instances', () => { expect( (new Schema({type: 'string'})) .sizeOf('hi') ) .to.equal(4 + (new TextEncoder().encode('hi')).length); expect( (new Schema( { type: 'object', properties: { foo: {type: 'uint8'}, bar: {type: 'uint32'}, baz: {type: 'string'}, }, }, )) .sizeOf({foo: 69, bar: 420, baz: 'aα'}) ) .to.equal( 1 + 4 + 4 + (new TextEncoder().encode('aα')).length ); expect( (new Schema({type: 'array', subtype: {type: 'string'}})) .sizeOf(['hallo', 'hαllo']) ) .to.equal( 4 + 4 + (new TextEncoder().encode('hallo')).length + 4 + (new TextEncoder().encode('hαllo')).length ); expect( (new Schema( { type: 'map', value: { type: 'object', properties: { foo: {type: 'uint8'}, bar: {type: 'uint32'}, baz: {type: 'string'}, }, }, }, )) .sizeOf({ foo: {foo: 69, bar: 420, baz: 'aα'}, 'aα': {foo: 69, bar: 420, baz: 'meow'}, }) ) .to.equal( 4 + 4 + (new TextEncoder().encode('foo')).length + 1 + 4 + 4 + (new TextEncoder().encode('aα')).length + 4 + (new TextEncoder().encode('aα')).length + 1 + 4 + 4 + (new TextEncoder().encode('meow')).length ); }); test('encodes and decodes', () => { const entries = [ [{type: 'uint8'}, 255], [{type: 'int8'}, -128], [{type: 'int8'}, 127], [{type: 'uint16'}, 65535], [{type: 'int16'}, -32768], [{type: 'int16'}, 32767], [{type: 'uint32'}, 4294967295], [{type: 'int32'}, -2147483648], [{type: 'int32'}, 2147483647], [{type: 'uint64'}, 18446744073709551615n], [{type: 'int64'}, -9223372036854775808n], [{type: 'int64'}, 9223372036854775807n], [{type: 'float32'}, 0.5], [{type: 'float64'}, 1.234], [{type: 'string'}, 'hello world'], [{type: 'string'}, 'α'], [{type: 'array', subtype: {type: 'uint8'}}, [1, 2, 3, 4]], [{type: 'array', subtype: {type: 'string'}}, ['one', 'two', 'three', 'four']], [{type: 'map', value: {type: 'object', properties: {foo: {type: 'uint8'}, bar: {type: 'string'}}}}, {one: {foo: 64, bar: 'baz'}, two: {foo: 128, bar: 'baw'}}], [{type: 'object', properties: {foo: {type: 'uint8'}, bar: {type: 'string'}}}, {foo: 64, bar: 'baz'}], [{type: 'object', properties: {foo: {type: 'uint8'}}}, {foo: 64}], ]; entries.forEach(([specification, instance]) => { const schema = new Schema(specification); const view = new DataView(new ArrayBuffer(schema.sizeOf(instance))); schema.serialize(instance, view); expect(instance) .to.deep.equal(schema.deserialize(view)); }); });