From 6d2c2bb8a1220e263b77137f439be8aa7dddb56a Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 21 Aug 2019 14:14:46 +0200 Subject: [PATCH] Cleanups & expand tests (#1330) * Vote cleanups & tests * VecFixed with tests & bugfixes --- packages/types/src/codec/Vec.spec.ts | 6 +++ packages/types/src/codec/VecFixed.spec.ts | 36 +++++++++++++ packages/types/src/codec/VecFixed.ts | 10 ++-- .../types/src/primitive/Generic/Origin.ts | 7 --- .../types/src/primitive/Generic/Vote.spec.ts | 32 ++++++++++++ packages/types/src/primitive/Generic/Vote.ts | 50 +++++++++++-------- 6 files changed, 111 insertions(+), 30 deletions(-) create mode 100644 packages/types/src/codec/VecFixed.spec.ts diff --git a/packages/types/src/codec/Vec.spec.ts b/packages/types/src/codec/Vec.spec.ts index c10962b565..247f254325 100644 --- a/packages/types/src/codec/Vec.spec.ts +++ b/packages/types/src/codec/Vec.spec.ts @@ -109,6 +109,12 @@ describe('Vec', (): void => { vector.reduce((r, e): string => `${r}${e}`, '') ).toEqual('123345456756789'); }); + + it('exposes a working indexOf', (): void => { + expect(vector.indexOf('1')).toEqual(0); + expect(vector.indexOf(new Text('23'))).toEqual(1); + expect(vector.indexOf('0')).toEqual(-1); + }); }); describe('encode', (): void => { diff --git a/packages/types/src/codec/VecFixed.spec.ts b/packages/types/src/codec/VecFixed.spec.ts new file mode 100644 index 0000000000..8473e7f96e --- /dev/null +++ b/packages/types/src/codec/VecFixed.spec.ts @@ -0,0 +1,36 @@ +// Copyright 2017-2019 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import Text from '../primitive/Text'; +import VecFixed from './VecFixed'; + +describe('VecFixed', (): void => { + describe('construction', (): void => { + it('constructs via empty', (): void => { + expect(new VecFixed(Text, 2).toHex()).toEqual('0x0000'); + }); + + it('constructs via Uint8Array', (): void => { + expect(new VecFixed(Text, 2, new Uint8Array([0x00, 0x04, 0x31])).toHex()).toEqual('0x000431'); + }); + }); + + describe('utils', (): void => { + let test: VecFixed; + + beforeEach((): void => { + test = new (VecFixed.with(Text, 5))(['1', '2', '3', undefined, '5']); + }); + + it('has a sane string types', (): void => { + expect(test.toRawType()).toEqual('[Text;5]'); + expect(test.Type).toEqual('Text'); + }); + + it('has a correct toHex', (): void => { + // each entry length 1 << 2, char as hex (0x31 === `1`), one empty + expect(test.toHex()).toEqual('0x043104320433000435'); + }); + }); +}); diff --git a/packages/types/src/codec/VecFixed.ts b/packages/types/src/codec/VecFixed.ts index 38b529b3d2..d2de010262 100644 --- a/packages/types/src/codec/VecFixed.ts +++ b/packages/types/src/codec/VecFixed.ts @@ -54,17 +54,21 @@ export default class VecFixed extends AbstractArray { * @description The type for the items */ public get Type (): string { - return this._Type.name; + return new this._Type().toRawType(); } public toU8a (): Uint8Array { - return super.toU8a(true); + // we override, we don't add the length prefix for outselves, and at the same time we + // ignore isBare on entries, since they should be properly encoded at all times + const encoded = this.map((entry): Uint8Array => entry.toU8a()); + + return u8aConcat(...encoded); } /** * @description Returns the base runtime type name for this instance */ public toRawType (): string { - return `[${new this._Type().toRawType()};${this.length}`; + return `[${this.Type};${this.length}]`; } } diff --git a/packages/types/src/primitive/Generic/Origin.ts b/packages/types/src/primitive/Generic/Origin.ts index 5ed4c84dbb..70bf691a44 100644 --- a/packages/types/src/primitive/Generic/Origin.ts +++ b/packages/types/src/primitive/Generic/Origin.ts @@ -16,11 +16,4 @@ export default class Origin extends Null { throw new Error('Origin should not be constructed, it is only a placeholder for compatibility'); } - - /** - * @description Returns the base runtime type name for this instance - */ - public toRawType (): string { - return 'Origin'; // yes, we cannot instantiate, but for consistency - } } diff --git a/packages/types/src/primitive/Generic/Vote.spec.ts b/packages/types/src/primitive/Generic/Vote.spec.ts index 174f7a6f21..e16da4107a 100644 --- a/packages/types/src/primitive/Generic/Vote.spec.ts +++ b/packages/types/src/primitive/Generic/Vote.spec.ts @@ -41,6 +41,25 @@ describe('Vote', (): void => { it('is Nay for 0', (): void => { expect(new Vote(0).isNay).toBe(true); }); + + it('constructs via empty', (): void => { + expect(new Vote().isNay).toBe(true); + }); + + it('constructs via Uint8Array (empty)', (): void => { + expect(new Vote(new Uint8Array()).isNay).toBe(true); + }); + + it('constructs via Uint8Array (nay)', (): void => { + expect(new Vote(new Uint8Array([1])).isNay).toBe(true); + }); + + it('constructs via Uint8Array (aye)', (): void => { + const test = new Vote(new Uint8Array([0b10000010])); + + expect(test.isNay).toBe(false); + expect(test.conviction.toString()).toEqual('Locked2x'); + }); }); describe('Vote with conviction', (): void => { @@ -100,6 +119,13 @@ describe('Vote', (): void => { ).toEqual('Locked2x'); }); + it('Conviction getter works with raw boolean and no conviction', (): void => { + const test = new Vote({ aye: true }); + + expect(test.isAye).toEqual(true); + expect(test.conviction.toString()).toEqual('None'); + }); + it('isAye getter works', (): void => { expect( new Vote({ @@ -118,4 +144,10 @@ describe('Vote', (): void => { .toEqual(false); }); }); + + describe('utils', (): void => { + it('has a sane toRawType', (): void => { + expect(new Vote().toRawType()).toEqual('Vote'); + }); + }); }); diff --git a/packages/types/src/primitive/Generic/Vote.ts b/packages/types/src/primitive/Generic/Vote.ts index 6c22ab4fd8..d2e457a1f9 100644 --- a/packages/types/src/primitive/Generic/Vote.ts +++ b/packages/types/src/primitive/Generic/Vote.ts @@ -4,12 +4,18 @@ import { Conviction } from '../../interfaces/democracy'; -import { isBoolean, isNumber, isObject, isU8a, isUndefined } from '@polkadot/util'; +import { isBoolean, isNumber, isU8a, isUndefined } from '@polkadot/util'; import { createType } from '../../codec/create'; import U8aFixed from '../../codec/U8aFixed'; import Bool from '../Bool'; +// eslint-disable-next-line @typescript-eslint/ban-types +type InputTypes = boolean | number | Boolean | Uint8Array | { + aye: boolean; + conviction?: number | ('None' | 'Locked1x' | 'Locked2x' | 'Locked3x' | 'Locked4x' | 'Locked5x'); +}; + // For votes, the topmost bit indicated aye/nay, the lower bits indicate the conviction const AYE_BITS = 0b10000000; const NAY_BITS = 0b00000000; @@ -26,7 +32,7 @@ export default class Vote extends U8aFixed { private _conviction: Conviction; - public constructor (value?: any) { + public constructor (value?: InputTypes) { // decoded is just 1 byte // Aye: Most Significant Bit // Conviction: 0000 - 0101 @@ -38,29 +44,33 @@ export default class Vote extends U8aFixed { this._conviction = createType('Conviction', decoded[0] & CON_MASK); } - private static decodeVote (value?: any): Uint8Array { + private static decodeVote (value?: InputTypes): Uint8Array { if (isUndefined(value)) { - return new Uint8Array([NAY_BITS]); - } else if (isBoolean(value)) { - return value - ? new Uint8Array([AYE_BITS | DEF_CONV]) - : new Uint8Array([NAY_BITS]); - } else if (value instanceof Boolean) { - return Vote.decodeVote(value.valueOf()); + return Vote.decodeVoteBool(false); + } else if (value instanceof Boolean || isBoolean(value)) { + return Vote.decodeVoteBool(new Bool(value).isTrue); } else if (isNumber(value)) { - return Vote.decodeVote(value < 0); + return Vote.decodeVoteBool(value < 0); } else if (isU8a(value)) { - return value.length - ? value.subarray(0, 1) - : new Uint8Array([NAY_BITS]); - } else if (isObject(value)) { - const vote = new Bool(value.aye).eq(true) ? AYE_BITS : NAY_BITS; - const conviction = createType('Conviction', isUndefined(value.conviction) ? DEF_CONV : value.conviction); - - return new Uint8Array([vote | conviction.index]); + return Vote.decodeVoteU8a(value); } - throw new Error(`Unable to convert input ${value} to Vote`); + const vote = new Bool(value.aye).isTrue ? AYE_BITS : NAY_BITS; + const conviction = createType('Conviction', isUndefined(value.conviction) ? DEF_CONV : value.conviction); + + return new Uint8Array([vote | conviction.index]); + } + + private static decodeVoteBool (value: boolean): Uint8Array { + return value + ? new Uint8Array([AYE_BITS | DEF_CONV]) + : new Uint8Array([NAY_BITS]); + } + + private static decodeVoteU8a (value: Uint8Array): Uint8Array { + return value.length + ? value.subarray(0, 1) + : new Uint8Array([NAY_BITS]); } /**