From ebfe260c7ab75b1c879245f9ea4893c872530f8f Mon Sep 17 00:00:00 2001 From: Kyle Peacock Date: Wed, 14 Dec 2022 16:45:03 -0800 Subject: [PATCH] simple test --- packages/candid/src/idl.test.ts | 29 ++++++++++++++++++++++++++++- packages/candid/src/idl.ts | 14 ++++++++++---- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/candid/src/idl.test.ts b/packages/candid/src/idl.test.ts index 7ab98b6b0..31a3edfb1 100644 --- a/packages/candid/src/idl.test.ts +++ b/packages/candid/src/idl.test.ts @@ -180,7 +180,9 @@ test('IDL encoding (arraybuffer)', () => { IDL.encode([IDL.Vec(IDL.Nat8)], [new Uint8Array()]); IDL.encode([IDL.Vec(IDL.Nat8)], [new Uint8Array(100).fill(42)]); IDL.encode([IDL.Vec(IDL.Nat16)], [new Uint16Array(200).fill(42)]); - expect(() => IDL.encode([IDL.Vec(IDL.Int8)], [new Uint16Array(10).fill(420)])).toThrow(/Invalid vec int8 argument/); + expect(() => IDL.encode([IDL.Vec(IDL.Int8)], [new Uint16Array(10).fill(420)])).toThrow( + /Invalid vec int8 argument/, + ); }); test('IDL encoding (array)', () => { @@ -641,6 +643,31 @@ test('decode / encode unknown nested record', () => { expect(decodedValue2).toEqual(value); }); +test.only('should allow records with missing optional fields', () => { + const ExtendedRecord = IDL.Record({ + foo: IDL.Int32, + bar: IDL.Bool, + bool: IDL.Opt(IDL.Bool), + int: IDL.Opt(IDL.Int), + nat: IDL.Opt(IDL.Nat), + nat32: IDL.Opt(IDL.Nat32), + nat64: IDL.Opt(IDL.Nat64), + float32: IDL.Opt(IDL.Float32), + float64: IDL.Opt(IDL.Float64), + text: IDL.Opt(IDL.Text), + null: IDL.Opt(IDL.Null), + reserved: IDL.Opt(IDL.Reserved), + principal: IDL.Opt(IDL.Principal), + nested: IDL.Opt(IDL.Opt(IDL.Nat)), + }); + + const encoded = IDL.encode([ExtendedRecord], [{ foo: 42, bar: true }]); + + expect(toHexString(encoded)).toMatchInlineSnapshot( + `"4449444c0d6e7c6e7d6e686e7e6e7f6e716e706e016e796e786e736e726c0ed3e3aa027e868eb70275ef99c00200e199cf0201ae9db1900102aa88ee88040387bdbac80404ad99e7e70405a8ed97f50406f7ddd8f80607c0e7a6b40908dfeca6b40909bba2a2d00e0adaa7a2d00e0b010c012a000000000000000000000000000000"`, + ); +}); + test('should correctly decode expected optional fields with lower hash than required fields', () => { const HttpResponse = IDL.Record({ body: IDL.Text, diff --git a/packages/candid/src/idl.ts b/packages/candid/src/idl.ts index 4b246da05..04ab81222 100644 --- a/packages/candid/src/idl.ts +++ b/packages/candid/src/idl.ts @@ -48,7 +48,9 @@ const magicNumber = 'DIDL'; const toReadableString_max = 400; // will not display arguments after 400chars. Makes sure 2mb blobs don't get inside the error function zipWith(xs: TX[], ys: TY[], f: (a: TX, b: TY) => TR): TR[] { - return xs.map((x, i) => f(x, ys[i])); + return xs.map((x, i) => { + return f(x, ys[i]); + }); } /** @@ -978,9 +980,13 @@ export class RecordClass extends ConstructType> { if ( typeof x === 'object' && this._fields.every(([k, t]) => { - // eslint-disable-next-line - if (!x.hasOwnProperty(k)) { - throw new Error(`Record is missing key "${k}".`); + if (!(k in x)) { + // Allow missing optional fields. + if (t instanceof OptClass) { + x[k] = []; + } else { + throw new Error(`Record is missing key "${k}".`); + } } try { return t.covariant(x[k]);