diff --git a/packages/protons-benchmark/src/protons/bench.ts b/packages/protons-benchmark/src/protons/bench.ts index efcdf84..877991e 100644 --- a/packages/protons-benchmark/src/protons/bench.ts +++ b/packages/protons-benchmark/src/protons/bench.ts @@ -159,7 +159,9 @@ export namespace Yo { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + lol: [] + } const end = length == null ? reader.len : reader.pos + length @@ -168,7 +170,6 @@ export namespace Yo { switch (tag >>> 3) { case 1: - obj.lol = obj.lol ?? [] obj.lol.push(FOO.codec().decode(reader)) break default: @@ -177,12 +178,6 @@ export namespace Yo { } } - obj.lol = obj.lol ?? [] - - if (obj.lol == null) { - throw new Error('Protocol error: value for required field "lol" was not found in protobuf') - } - return obj }) } @@ -230,7 +225,9 @@ export namespace Lol { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + b: undefined + } const end = length == null ? reader.len : reader.pos + length diff --git a/packages/protons-runtime/src/index.ts b/packages/protons-runtime/src/index.ts index 095bf20..54ac86b 100644 --- a/packages/protons-runtime/src/index.ts +++ b/packages/protons-runtime/src/index.ts @@ -180,12 +180,12 @@ export interface Reader { double: () => number /** - * Reads a sequence of bytes preceeded by its length as a varint + * Reads a sequence of bytes preceded by its length as a varint */ - bytes: () => number + bytes: () => Uint8Array /** - * Reads a string preceeded by its byte length as a varint + * Reads a string preceded by its byte length as a varint */ string: () => string diff --git a/packages/protons/src/index.ts b/packages/protons/src/index.ts index 2b03b25..385b91c 100644 --- a/packages/protons/src/index.ts +++ b/packages/protons/src/index.ts @@ -39,7 +39,6 @@ const encoderGenerators: Record string> = { bool: (val) => `writer.bool(${val})`, bytes: (val) => `writer.bytes(${val})`, double: (val) => `writer.double(${val})`, - // enumeration: (val) => `writer.double(${val})`, fixed32: (val) => `writer.fixed32(${val})`, fixed64: (val) => `writer.fixed64(${val})`, float: (val) => `writer.float(${val})`, @@ -58,7 +57,6 @@ const decoderGenerators: Record string> = { bool: () => 'reader.bool()', bytes: () => 'reader.bytes()', double: () => 'reader.double()', - // enumeration: () => `writer.double(${val})`, fixed32: () => 'reader.fixed32()', fixed64: () => 'reader.fixed64()', float: () => 'reader.float()', @@ -73,6 +71,24 @@ const decoderGenerators: Record string> = { uint64: () => 'reader.uint64()' } +const defaultValueGenerators: Record string> = { + bool: () => 'false', + bytes: () => 'new Uint8Array(0)', + double: () => '0', + fixed32: () => '0', + fixed64: () => '0n', + float: () => '0', + int32: () => '0', + int64: () => '0n', + sfixed32: () => '0', + sfixed64: () => '0n', + sint32: () => '0', + sint64: () => '0n', + string: () => "''", + uint32: () => '0', + uint64: () => '0n' +} + function findTypeName (typeName: string, classDef: MessageDef, moduleDef: ModuleDef): string { if (types[typeName] != null) { return types[typeName] @@ -117,6 +133,65 @@ function findDef (typeName: string, classDef: MessageDef, moduleDef: ModuleDef): throw new Error(`Could not resolve type name "${typeName}"`) } +function createDefaultObject (fields: Record, messageDef: MessageDef, moduleDef: ModuleDef): string { + const output = Object.entries(fields) + .map(([name, fieldDef]) => { + if (fieldDef.repeated) { + return `${name}: []` + } + + if (fieldDef.optional) { + return '' + } + + const type: string = fieldDef.type + let defaultValue + + if (defaultValueGenerators[type] != null) { + defaultValue = defaultValueGenerators[type]() + } else { + const def = findDef(fieldDef.type, messageDef, moduleDef) + + if (isEnumDef(def)) { + // select lowest-value enum - should be 0 but it's not guaranteed + const val = Object.entries(def.values) + .sort((a, b) => { + if (a[1] < b[1]) { + return 1 + } + + if (a[1] > b[1]) { + return -1 + } + + return 0 + }) + .pop() + + if (val == null) { + throw new Error(`Could not find default enum value for ${def.fullName}`) + } + + defaultValue = `${def.name}.${val[0]}` + } else { + defaultValue = 'undefined' + } + } + + return `${name}: ${defaultValue}` + }) + .filter(Boolean) + .join(',\n ') + + if (output !== '') { + return ` + ${output} + ` + } + + return '' +} + const encoders: Record = { bool: 'bool', bytes: 'bytes', @@ -259,7 +334,7 @@ export interface ${messageDef.name} { const ensureArrayProps = Object.entries(fields) .map(([name, fieldDef]) => { // make sure repeated fields have an array if not set - if (fieldDef.rule === 'repeated') { + if (fieldDef.optional && fieldDef.rule === 'repeated') { return ` obj.${name} = obj.${name} ?? []` } @@ -269,7 +344,7 @@ export interface ${messageDef.name} { const ensureRequiredFields = Object.entries(fields) .map(([name, fieldDef]) => { // make sure required fields are set - if (!fieldDef.optional) { + if (!fieldDef.optional && !fieldDef.repeated) { return ` if (obj.${name} == null) { throw new Error('Protocol error: value for required field "${name}" was not found in protobuf') @@ -331,7 +406,7 @@ ${Object.entries(fields) writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = {${createDefaultObject(fields, messageDef, moduleDef)}} const end = length == null ? reader.len : reader.pos + length @@ -360,8 +435,10 @@ ${Object.entries(fields) } return `case ${fieldDef.id}:${fieldDef.rule === 'repeated' +? `${fieldDef.optional ? ` - obj.${name} = obj.${name} ?? [] + obj.${name} = obj.${name} ?? []` +: ''} obj.${name}.push(${decoderGenerators[type] == null ? `${codec}.decode(reader${type === 'message' ? ', reader.uint32()' : ''})` : decoderGenerators[type]()})` : ` obj.${name} = ${decoderGenerators[type] == null ? `${codec}.decode(reader${type === 'message' ? ', reader.uint32()' : ''})` : decoderGenerators[type]()}`} diff --git a/packages/protons/test/fixtures/basic.proto b/packages/protons/test/fixtures/basic.proto index 55882d4..83fbc41 100644 --- a/packages/protons/test/fixtures/basic.proto +++ b/packages/protons/test/fixtures/basic.proto @@ -2,5 +2,5 @@ syntax = "proto3"; message Basic { optional string foo = 1; - required int32 num = 2; + int32 num = 2; } diff --git a/packages/protons/test/fixtures/basic.ts b/packages/protons/test/fixtures/basic.ts index 0950495..5e6a1a2 100644 --- a/packages/protons/test/fixtures/basic.ts +++ b/packages/protons/test/fixtures/basic.ts @@ -36,7 +36,9 @@ export namespace Basic { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + num: 0 + } const end = length == null ? reader.len : reader.pos + length diff --git a/packages/protons/test/fixtures/circuit.ts b/packages/protons/test/fixtures/circuit.ts index 44b0127..6567544 100644 --- a/packages/protons/test/fixtures/circuit.ts +++ b/packages/protons/test/fixtures/circuit.ts @@ -112,7 +112,10 @@ export namespace CircuitRelay { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + id: new Uint8Array(0), + addrs: [] + } const end = length == null ? reader.len : reader.pos + length @@ -124,7 +127,6 @@ export namespace CircuitRelay { obj.id = reader.bytes() break case 2: - obj.addrs = obj.addrs ?? [] obj.addrs.push(reader.bytes()) break default: @@ -133,16 +135,10 @@ export namespace CircuitRelay { } } - obj.addrs = obj.addrs ?? [] - if (obj.id == null) { throw new Error('Protocol error: value for required field "id" was not found in protobuf') } - if (obj.addrs == null) { - throw new Error('Protocol error: value for required field "addrs" was not found in protobuf') - } - return obj }) } diff --git a/packages/protons/test/fixtures/daemon.ts b/packages/protons/test/fixtures/daemon.ts index e2f0627..32080ca 100644 --- a/packages/protons/test/fixtures/daemon.ts +++ b/packages/protons/test/fixtures/daemon.ts @@ -110,7 +110,9 @@ export namespace Request { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + type: Type.IDENTIFY + } const end = length == null ? reader.len : reader.pos + length @@ -258,7 +260,10 @@ export namespace Response { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + type: Type.OK, + peers: [] + } const end = length == null ? reader.len : reader.pos + length @@ -282,7 +287,6 @@ export namespace Response { obj.dht = DHTResponse.codec().decode(reader, reader.uint32()) break case 6: - obj.peers = obj.peers ?? [] obj.peers.push(PeerInfo.codec().decode(reader, reader.uint32())) break case 7: @@ -297,16 +301,10 @@ export namespace Response { } } - obj.peers = obj.peers ?? [] - if (obj.type == null) { throw new Error('Protocol error: value for required field "type" was not found in protobuf') } - if (obj.peers == null) { - throw new Error('Protocol error: value for required field "peers" was not found in protobuf') - } - return obj }) } @@ -358,7 +356,10 @@ export namespace IdentifyResponse { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + id: new Uint8Array(0), + addrs: [] + } const end = length == null ? reader.len : reader.pos + length @@ -370,7 +371,6 @@ export namespace IdentifyResponse { obj.id = reader.bytes() break case 2: - obj.addrs = obj.addrs ?? [] obj.addrs.push(reader.bytes()) break default: @@ -379,16 +379,10 @@ export namespace IdentifyResponse { } } - obj.addrs = obj.addrs ?? [] - if (obj.id == null) { throw new Error('Protocol error: value for required field "id" was not found in protobuf') } - if (obj.addrs == null) { - throw new Error('Protocol error: value for required field "addrs" was not found in protobuf') - } - return obj }) } @@ -446,7 +440,10 @@ export namespace ConnectRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + peer: new Uint8Array(0), + addrs: [] + } const end = length == null ? reader.len : reader.pos + length @@ -458,7 +455,6 @@ export namespace ConnectRequest { obj.peer = reader.bytes() break case 2: - obj.addrs = obj.addrs ?? [] obj.addrs.push(reader.bytes()) break case 3: @@ -470,16 +466,10 @@ export namespace ConnectRequest { } } - obj.addrs = obj.addrs ?? [] - if (obj.peer == null) { throw new Error('Protocol error: value for required field "peer" was not found in protobuf') } - if (obj.addrs == null) { - throw new Error('Protocol error: value for required field "addrs" was not found in protobuf') - } - return obj }) } @@ -537,7 +527,10 @@ export namespace StreamOpenRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + peer: new Uint8Array(0), + proto: [] + } const end = length == null ? reader.len : reader.pos + length @@ -549,7 +542,6 @@ export namespace StreamOpenRequest { obj.peer = reader.bytes() break case 2: - obj.proto = obj.proto ?? [] obj.proto.push(reader.string()) break case 3: @@ -561,16 +553,10 @@ export namespace StreamOpenRequest { } } - obj.proto = obj.proto ?? [] - if (obj.peer == null) { throw new Error('Protocol error: value for required field "peer" was not found in protobuf') } - if (obj.proto == null) { - throw new Error('Protocol error: value for required field "proto" was not found in protobuf') - } - return obj }) } @@ -622,7 +608,10 @@ export namespace StreamHandlerRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + addr: new Uint8Array(0), + proto: [] + } const end = length == null ? reader.len : reader.pos + length @@ -634,7 +623,6 @@ export namespace StreamHandlerRequest { obj.addr = reader.bytes() break case 2: - obj.proto = obj.proto ?? [] obj.proto.push(reader.string()) break default: @@ -643,16 +631,10 @@ export namespace StreamHandlerRequest { } } - obj.proto = obj.proto ?? [] - if (obj.addr == null) { throw new Error('Protocol error: value for required field "addr" was not found in protobuf') } - if (obj.proto == null) { - throw new Error('Protocol error: value for required field "proto" was not found in protobuf') - } - return obj }) } @@ -694,7 +676,9 @@ export namespace ErrorResponse { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + msg: '' + } const end = length == null ? reader.len : reader.pos + length @@ -772,7 +756,11 @@ export namespace StreamInfo { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + peer: new Uint8Array(0), + addr: new Uint8Array(0), + proto: '' + } const end = length == null ? reader.len : reader.pos + length @@ -914,7 +902,9 @@ export namespace DHTRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + type: Type.FIND_PEER + } const end = length == null ? reader.len : reader.pos + length @@ -1024,7 +1014,9 @@ export namespace DHTResponse { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + type: Type.BEGIN + } const end = length == null ? reader.len : reader.pos + length @@ -1102,7 +1094,10 @@ export namespace PeerInfo { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + id: new Uint8Array(0), + addrs: [] + } const end = length == null ? reader.len : reader.pos + length @@ -1114,7 +1109,6 @@ export namespace PeerInfo { obj.id = reader.bytes() break case 2: - obj.addrs = obj.addrs ?? [] obj.addrs.push(reader.bytes()) break default: @@ -1123,16 +1117,10 @@ export namespace PeerInfo { } } - obj.addrs = obj.addrs ?? [] - if (obj.id == null) { throw new Error('Protocol error: value for required field "id" was not found in protobuf') } - if (obj.addrs == null) { - throw new Error('Protocol error: value for required field "addrs" was not found in protobuf') - } - return obj }) } @@ -1210,7 +1198,9 @@ export namespace ConnManagerRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + type: Type.TAG_PEER + } const end = length == null ? reader.len : reader.pos + length @@ -1281,7 +1271,9 @@ export namespace DisconnectRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + peer: new Uint8Array(0) + } const end = length == null ? reader.len : reader.pos + length @@ -1375,7 +1367,9 @@ export namespace PSRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + type: Type.GET_TOPICS + } const end = length == null ? reader.len : reader.pos + length @@ -1475,7 +1469,9 @@ export namespace PSMessage { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + topicIDs: [] + } const end = length == null ? reader.len : reader.pos + length @@ -1493,7 +1489,6 @@ export namespace PSMessage { obj.seqno = reader.bytes() break case 4: - obj.topicIDs = obj.topicIDs ?? [] obj.topicIDs.push(reader.string()) break case 5: @@ -1508,12 +1503,6 @@ export namespace PSMessage { } } - obj.topicIDs = obj.topicIDs ?? [] - - if (obj.topicIDs == null) { - throw new Error('Protocol error: value for required field "topicIDs" was not found in protobuf') - } - return obj }) } @@ -1567,7 +1556,10 @@ export namespace PSResponse { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + topics: [], + peerIDs: [] + } const end = length == null ? reader.len : reader.pos + length @@ -1576,11 +1568,9 @@ export namespace PSResponse { switch (tag >>> 3) { case 1: - obj.topics = obj.topics ?? [] obj.topics.push(reader.string()) break case 2: - obj.peerIDs = obj.peerIDs ?? [] obj.peerIDs.push(reader.bytes()) break default: @@ -1589,17 +1579,6 @@ export namespace PSResponse { } } - obj.topics = obj.topics ?? [] - obj.peerIDs = obj.peerIDs ?? [] - - if (obj.topics == null) { - throw new Error('Protocol error: value for required field "topics" was not found in protobuf') - } - - if (obj.peerIDs == null) { - throw new Error('Protocol error: value for required field "peerIDs" was not found in protobuf') - } - return obj }) } @@ -1673,7 +1652,10 @@ export namespace PeerstoreRequest { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + type: Type.GET_PROTOCOLS, + protos: [] + } const end = length == null ? reader.len : reader.pos + length @@ -1688,7 +1670,6 @@ export namespace PeerstoreRequest { obj.id = reader.bytes() break case 3: - obj.protos = obj.protos ?? [] obj.protos.push(reader.string()) break default: @@ -1697,16 +1678,10 @@ export namespace PeerstoreRequest { } } - obj.protos = obj.protos ?? [] - if (obj.type == null) { throw new Error('Protocol error: value for required field "type" was not found in protobuf') } - if (obj.protos == null) { - throw new Error('Protocol error: value for required field "protos" was not found in protobuf') - } - return obj }) } @@ -1756,7 +1731,9 @@ export namespace PeerstoreResponse { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + protos: [] + } const end = length == null ? reader.len : reader.pos + length @@ -1768,7 +1745,6 @@ export namespace PeerstoreResponse { obj.peer = PeerInfo.codec().decode(reader, reader.uint32()) break case 2: - obj.protos = obj.protos ?? [] obj.protos.push(reader.string()) break default: @@ -1777,12 +1753,6 @@ export namespace PeerstoreResponse { } } - obj.protos = obj.protos ?? [] - - if (obj.protos == null) { - throw new Error('Protocol error: value for required field "protos" was not found in protobuf') - } - return obj }) } diff --git a/packages/protons/test/fixtures/dht.ts b/packages/protons/test/fixtures/dht.ts index fc278a9..afbe4e2 100644 --- a/packages/protons/test/fixtures/dht.ts +++ b/packages/protons/test/fixtures/dht.ts @@ -190,7 +190,9 @@ export namespace Message { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + addrs: [] + } const end = length == null ? reader.len : reader.pos + length @@ -202,7 +204,6 @@ export namespace Message { obj.id = reader.bytes() break case 2: - obj.addrs = obj.addrs ?? [] obj.addrs.push(reader.bytes()) break case 3: @@ -214,12 +215,6 @@ export namespace Message { } } - obj.addrs = obj.addrs ?? [] - - if (obj.addrs == null) { - throw new Error('Protocol error: value for required field "addrs" was not found in protobuf') - } - return obj }) } @@ -287,7 +282,10 @@ export namespace Message { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + closerPeers: [], + providerPeers: [] + } const end = length == null ? reader.len : reader.pos + length @@ -308,11 +306,9 @@ export namespace Message { obj.record = reader.bytes() break case 8: - obj.closerPeers = obj.closerPeers ?? [] obj.closerPeers.push(Message.Peer.codec().decode(reader, reader.uint32())) break case 9: - obj.providerPeers = obj.providerPeers ?? [] obj.providerPeers.push(Message.Peer.codec().decode(reader, reader.uint32())) break default: @@ -321,17 +317,6 @@ export namespace Message { } } - obj.closerPeers = obj.closerPeers ?? [] - obj.providerPeers = obj.providerPeers ?? [] - - if (obj.closerPeers == null) { - throw new Error('Protocol error: value for required field "closerPeers" was not found in protobuf') - } - - if (obj.providerPeers == null) { - throw new Error('Protocol error: value for required field "providerPeers" was not found in protobuf') - } - return obj }) } diff --git a/packages/protons/test/fixtures/noise.ts b/packages/protons/test/fixtures/noise.ts index 0bdada6..0d1af33 100644 --- a/packages/protons/test/fixtures/noise.ts +++ b/packages/protons/test/fixtures/noise.ts @@ -47,7 +47,11 @@ export namespace pb { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + identityKey: new Uint8Array(0), + identitySig: new Uint8Array(0), + data: new Uint8Array(0) + } const end = length == null ? reader.len : reader.pos + length diff --git a/packages/protons/test/fixtures/peer.ts b/packages/protons/test/fixtures/peer.ts index 68bd477..f9357a3 100644 --- a/packages/protons/test/fixtures/peer.ts +++ b/packages/protons/test/fixtures/peer.ts @@ -64,7 +64,11 @@ export namespace Peer { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + addresses: [], + protocols: [], + metadata: [] + } const end = length == null ? reader.len : reader.pos + length @@ -73,15 +77,12 @@ export namespace Peer { switch (tag >>> 3) { case 1: - obj.addresses = obj.addresses ?? [] obj.addresses.push(Address.codec().decode(reader, reader.uint32())) break case 2: - obj.protocols = obj.protocols ?? [] obj.protocols.push(reader.string()) break case 3: - obj.metadata = obj.metadata ?? [] obj.metadata.push(Metadata.codec().decode(reader, reader.uint32())) break case 4: @@ -96,22 +97,6 @@ export namespace Peer { } } - obj.addresses = obj.addresses ?? [] - obj.protocols = obj.protocols ?? [] - obj.metadata = obj.metadata ?? [] - - if (obj.addresses == null) { - throw new Error('Protocol error: value for required field "addresses" was not found in protobuf') - } - - if (obj.protocols == null) { - throw new Error('Protocol error: value for required field "protocols" was not found in protobuf') - } - - if (obj.metadata == null) { - throw new Error('Protocol error: value for required field "metadata" was not found in protobuf') - } - return obj }) } @@ -159,7 +144,9 @@ export namespace Address { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + multiaddr: new Uint8Array(0) + } const end = length == null ? reader.len : reader.pos + length @@ -232,7 +219,10 @@ export namespace Metadata { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + key: '', + value: new Uint8Array(0) + } const end = length == null ? reader.len : reader.pos + length diff --git a/packages/protons/test/fixtures/test.ts b/packages/protons/test/fixtures/test.ts index eea1650..3ca17c9 100644 --- a/packages/protons/test/fixtures/test.ts +++ b/packages/protons/test/fixtures/test.ts @@ -45,7 +45,9 @@ export namespace SubMessage { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + foo: '' + } const end = length == null ? reader.len : reader.pos + length @@ -211,7 +213,9 @@ export namespace AllTheTypes { writer.ldelim() } }, (reader, length) => { - const obj: any = {} + const obj: any = { + field14: [] + } const end = length == null ? reader.len : reader.pos + length @@ -259,7 +263,6 @@ export namespace AllTheTypes { obj.field13 = SubMessage.codec().decode(reader, reader.uint32()) break case 14: - obj.field14 = obj.field14 ?? [] obj.field14.push(reader.string()) break case 15: @@ -280,12 +283,6 @@ export namespace AllTheTypes { } } - obj.field14 = obj.field14 ?? [] - - if (obj.field14 == null) { - throw new Error('Protocol error: value for required field "field14" was not found in protobuf') - } - return obj }) } diff --git a/packages/protons/test/index.spec.ts b/packages/protons/test/index.spec.ts index 060c8d6..e6a8756 100644 --- a/packages/protons/test/index.spec.ts +++ b/packages/protons/test/index.spec.ts @@ -180,4 +180,23 @@ describe('encode', () => { expect(CircuitRelay.decode(encoded)).to.deep.equal(message) expect(CircuitRelay.decode(pbufJsBuf)).to.deep.equal(message) }) + + it('supports optional fields', () => { + const obj: Basic = { + num: 5 + } + + const encoded = Basic.encode(obj) + const decoded = Basic.decode(encoded) + + // foo is optional + expect(decoded).to.not.have.property('foo') + }) + + it('supports default fields', () => { + const decoded = Basic.decode(Uint8Array.from([])) + + // num is required + expect(decoded).to.have.property('num', 0) + }) })