Add .eq to Codec (#622)
* Add .eq to Codec * Tests for Codec .eq * Extra ()'s around checks * Update AbstractInt.ts * Use .size in Map compare * Equivalency comment * Update Compact.eq to user wrapper eq
This commit is contained in:
@@ -20,6 +20,10 @@ describe('AccountId', () => {
|
||||
it('is empty by default', () => {
|
||||
expect(id.isEmpty).toBe(true);
|
||||
});
|
||||
|
||||
it('equals the empty address', () => {
|
||||
expect(id.eq('5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUppTZ')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decoding', () => {
|
||||
|
||||
@@ -40,6 +40,13 @@ export default class AccountId extends U8aFixed {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return super.eq(AccountId.decodeAccountId(other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Converts the Object to JSON, typically used for RPC transfers
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,14 @@ describe('AccountIndex', () => {
|
||||
).toEqual('Mwz15xN8');
|
||||
});
|
||||
|
||||
it('compares ss-58 values', () => {
|
||||
expect(new AccountIndex(256 * 1).eq('25GUyk')).toBe(true);
|
||||
});
|
||||
|
||||
it('compares numbers', () => {
|
||||
expect(new AccountIndex('25GUyk').eq(256 * 1)).toBe(true);
|
||||
});
|
||||
|
||||
describe('calcLength', () => {
|
||||
const testLength = (value: number, length: number) =>
|
||||
expect(AccountIndex.calcLength(value)).toEqual(length);
|
||||
|
||||
@@ -86,6 +86,19 @@ export default class AccountIndex extends U32 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
// shortcut for BN or Number, don't create an object
|
||||
if (isBn(other) || isNumber(other)) {
|
||||
return super.eq(other);
|
||||
}
|
||||
|
||||
// convert and compare
|
||||
return super.eq(new AccountIndex(other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,19 @@ describe('Address', () => {
|
||||
expect(a.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
describe('utility', () => {
|
||||
it('equals on AccountId', () => {
|
||||
const addr = '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s';
|
||||
|
||||
expect(new Address(addr).eq(addr)).toBe(true);
|
||||
});
|
||||
|
||||
it('equals on AccountIndex', () => {
|
||||
// see the test below - these are equivalent (with different prefix encoding)
|
||||
expect(new Address('PrF3').eq('F7ih')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decoding', () => {
|
||||
testDecode(
|
||||
'Address',
|
||||
|
||||
@@ -84,6 +84,13 @@ export default class Address extends Base<AccountId | AccountIndex> {
|
||||
: this.raw.encodedLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return this.raw.eq(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -34,4 +34,14 @@ describe('Bool', () => {
|
||||
it('correctly encodes length', () => {
|
||||
expect(new Bool(true).encodedLength).toEqual(1);
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares agains a boolean', () => {
|
||||
expect(new Bool(true).eq(true)).toBe(true);
|
||||
});
|
||||
|
||||
it('compares agains a Bool', () => {
|
||||
expect(new Bool(false).eq(new Bool(false))).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,6 +36,17 @@ export default class Bool extends Boolean implements Codec {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return this.valueOf() === (
|
||||
other instanceof Boolean
|
||||
? other.valueOf()
|
||||
: other
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -19,4 +19,13 @@ describe('ChainProperties', () => {
|
||||
}).entries()]
|
||||
).toEqual([['decimals', 15], ['tokenSymbol', 'BBQ']]);
|
||||
});
|
||||
|
||||
it('checks equality', () => {
|
||||
expect(
|
||||
new ChainProperties({
|
||||
decimals: 15,
|
||||
tokenSymbol: 'BBQ'
|
||||
}).eq([['tokenSymbol', 'BBQ'], ['decimals', 15]])
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Codec } from './types';
|
||||
import { compareMap } from './codec/utils';
|
||||
|
||||
// TODO Expose known properties as they become known, currently we have `tokenSymbol` (e.g. BBQ)
|
||||
|
||||
@@ -38,6 +39,13 @@ export default class ChainProperties extends Map<string, any> implements Codec {
|
||||
return super.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return compareMap(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Unimplemented, will throw
|
||||
*/
|
||||
|
||||
@@ -42,4 +42,14 @@ describe('Moment', () => {
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares values', () => {
|
||||
expect(new Moment(123).eq(123)).toBe(true);
|
||||
});
|
||||
|
||||
it('compares values (non-match)', () => {
|
||||
expect(new Moment(123).eq(456)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -52,6 +52,13 @@ export default class Moment extends Date implements Codec {
|
||||
return BITLENGTH / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return Moment.decodeMoment(other).getTime() === this.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the number of bits in the value
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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 Null from './Null';
|
||||
|
||||
describe('Null', () => {
|
||||
it('compares against null', () => {
|
||||
expect(new Null().eq(null)).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against Null', () => {
|
||||
expect(new Null().eq(new Null())).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against other (failed)', () => {
|
||||
expect(new Null().eq()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Codec } from './types';
|
||||
import { isNull } from '@polkadot/util';
|
||||
|
||||
/**
|
||||
* @name Null
|
||||
@@ -17,6 +18,13 @@ export default class Null implements Codec {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return other instanceof Null || isNull(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -30,4 +30,18 @@ describe('Text', () => {
|
||||
testEncode('toString', 'foo');
|
||||
testEncode('toU8a', Uint8Array.from([12, 102, 111, 111]));
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares actual string values', () => {
|
||||
expect(new Text('123').eq('123')).toBe(true);
|
||||
});
|
||||
|
||||
it('compares actual String values', () => {
|
||||
expect(new Text('XYX').eq(new String('XYX'))).toBe(true);
|
||||
});
|
||||
|
||||
it('compares actual non-string values (fails)', () => {
|
||||
expect(new Text('123').eq(123)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,6 +56,15 @@ export default class Text extends String implements Codec {
|
||||
return super.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return isString(other)
|
||||
? this.toString() === other.toString()
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@ export const DEFAULT_UINT_BITS = 64;
|
||||
export default abstract class AbstractInt extends BN implements Codec {
|
||||
protected _bitLength: UIntBitLength;
|
||||
private _isHexJson: boolean;
|
||||
private _isNegative: boolean;
|
||||
|
||||
constructor (
|
||||
isNegative: boolean,
|
||||
@@ -32,6 +33,7 @@ export default abstract class AbstractInt extends BN implements Codec {
|
||||
|
||||
this._bitLength = bitLength;
|
||||
this._isHexJson = isHexJson;
|
||||
this._isNegative = isNegative;
|
||||
}
|
||||
|
||||
static decodeAbstracInt (value: AnyNumber, bitLength: UIntBitLength, isNegative: boolean): string {
|
||||
@@ -70,6 +72,19 @@ export default abstract class AbstractInt extends BN implements Codec {
|
||||
return this._bitLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
// Here we are actually overriding the built-in .eq to take care of both
|
||||
// number and BN inputs (no `.eqn` needed) - numbers will be converted
|
||||
return super.eq(
|
||||
isHex(other)
|
||||
? hexToBn(other.toString(), { isLe: false, isNegative: this._isNegative })
|
||||
: bnToBn(other)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the BN representation of the number. (Compatibility)
|
||||
*/
|
||||
|
||||
@@ -137,6 +137,16 @@ describe('Compact', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares against another Compact', () => {
|
||||
expect(new Compact(U32, 12345).eq(new Compact(U32, 12345))).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against a primitive', () => {
|
||||
expect(new Compact(U32, 12345).eq(12345)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('helpers', () => {
|
||||
it('correctly adds the length prefix', () => {
|
||||
expect(
|
||||
|
||||
@@ -80,6 +80,17 @@ export default class Compact extends Base<UInt | Moment> implements Codec {
|
||||
return this.raw.bitLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return this.raw.eq(
|
||||
other instanceof Compact
|
||||
? other.raw
|
||||
: other
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the BN representation of the number
|
||||
*/
|
||||
|
||||
@@ -53,4 +53,30 @@ describe('Enum', () => {
|
||||
new Enum(['foo', 'bar'], 5).toString()
|
||||
).toEqual('5');
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares agains the index value', () => {
|
||||
expect(
|
||||
new Enum(['foo', 'bar'], 1).eq(1)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares agains the index value (false)', () => {
|
||||
expect(
|
||||
new Enum(['foo', 'bar'], 1).eq(0)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('compares agains the string value', () => {
|
||||
expect(
|
||||
new Enum(['foo', 'bar'], 1).eq('bar')
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares agains the string value (false)', () => {
|
||||
expect(
|
||||
new Enum(['foo', 'bar'], 1).eq('foo')
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,6 +65,19 @@ export default class Enum extends Base<number> implements Codec {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
if (other instanceof Enum) {
|
||||
return this.raw === other.raw;
|
||||
}
|
||||
|
||||
return isString(other)
|
||||
? this.toString() === other
|
||||
: this.raw === other;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -84,4 +84,23 @@ describe('Struct', () => {
|
||||
expect(enumType.type).toBe('Text');
|
||||
expect(enumType.value).toEqual(text);
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
const eqtest = new EnumType(
|
||||
{ U32, Text },
|
||||
new Uint8Array([1, 3 << 2, 88, 89, 90])
|
||||
);
|
||||
|
||||
it('compares against index', () => {
|
||||
expect(
|
||||
eqtest.eq(1)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against values', () => {
|
||||
expect(
|
||||
eqtest.eq('XYZ')
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -130,6 +130,19 @@ export default class EnumType<T> extends Base<Codec> implements Codec {
|
||||
return this.raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
// cater for the case where we only pass the enum index
|
||||
if (isNumber(other)) {
|
||||
return this.toNumber() === other;
|
||||
}
|
||||
|
||||
// compare the actual wrapper value
|
||||
return this.value.eq(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import Option from './Option';
|
||||
import Text from '../Text';
|
||||
|
||||
const testDecode = (type, input, expected) =>
|
||||
const testDecode = (type: string, input: any, expected: any) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const o = new Option(Text, input);
|
||||
|
||||
@@ -13,11 +13,11 @@ const testDecode = (type, input, expected) =>
|
||||
expect(o.isNone).toBe(!expected.length);
|
||||
});
|
||||
|
||||
const testEncode = (to, expected) =>
|
||||
const testEncode = (to: string, expected: any) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const e = new Option(Text, 'foo');
|
||||
|
||||
expect(e[to]()).toEqual(expected);
|
||||
expect((e as any)[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
describe('Option', () => {
|
||||
@@ -36,7 +36,7 @@ describe('Option', () => {
|
||||
testDecode('string (with)', 'foo', 'foo');
|
||||
testDecode('string (without)', undefined, '');
|
||||
testDecode('Uint8Array (with)', Uint8Array.from([1, 12, 102, 111, 111]), 'foo');
|
||||
testDecode('Uint8Array (without)', Uint8Array.from([0]), '', false);
|
||||
testDecode('Uint8Array (without)', Uint8Array.from([0]), '');
|
||||
|
||||
testEncode('toHex', '0x010c666f6f');
|
||||
testEncode('toString', 'foo');
|
||||
@@ -65,4 +65,16 @@ describe('Option', () => {
|
||||
new Option(Text).toU8a()
|
||||
).toEqual(new Uint8Array([0]));
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
const testeq = new Option(Text, '1234');
|
||||
|
||||
it('compares against other option', () => {
|
||||
expect(testeq.eq(new Option(Text, '1234'))).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against raw value', () => {
|
||||
expect(testeq.eq('1234')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -75,6 +75,17 @@ export default class Option<T extends Codec> extends Base<T> implements Codec {
|
||||
return this.raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
if (other instanceof Option) {
|
||||
return (this.isSome === other.isSome) && this.value.eq(other.value);
|
||||
}
|
||||
|
||||
return this.value.eq(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -42,4 +42,32 @@ describe('Set', () => {
|
||||
|
||||
expect(set.toU8a()).toEqual(new Uint8Array([19]));
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
const set = new Set(SET_ROLES, ['full', 'authority']);
|
||||
|
||||
it('compares against string array', () => {
|
||||
expect(
|
||||
set.eq(['authority', 'full'])
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against number (encoded)', () => {
|
||||
expect(
|
||||
set.eq(SET_ROLES.full | SET_ROLES.authority)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against other sets', () => {
|
||||
expect(
|
||||
set.eq(new Set(SET_ROLES, ['authority', 'full']))
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false on other values', () => {
|
||||
expect(
|
||||
set.eq('full')
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { isU8a, isUndefined, u8aToHex } from '@polkadot/util';
|
||||
import { isU8a, isNumber, isUndefined, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import Base from './Base';
|
||||
import { Codec } from '../types';
|
||||
import { compareArray } from './utils';
|
||||
|
||||
type SetValues = {
|
||||
[index: string]: number
|
||||
@@ -94,6 +95,22 @@ export default class Set extends Base<Array<string>> implements Codec {
|
||||
return Set.encodeSet(this._setValues, this.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
if (Array.isArray(other)) {
|
||||
// we don't actually care about the order, sort the values
|
||||
return compareArray(this.values.sort(), other.sort());
|
||||
} else if (other instanceof Set) {
|
||||
return this.eq(other.values);
|
||||
} else if (isNumber(other)) {
|
||||
return this.valueEncoded === other;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
@@ -154,4 +154,22 @@ describe('Struct', () => {
|
||||
.toString()
|
||||
).toEqual('1234');
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares against other objects', () => {
|
||||
const test = {
|
||||
foo: 'foo',
|
||||
bar: 'bar',
|
||||
baz: 3
|
||||
};
|
||||
|
||||
expect(
|
||||
new Struct({
|
||||
foo: Text,
|
||||
bar: Text,
|
||||
baz: U32
|
||||
}, test).eq(test)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { hexToU8a, isHex, isObject, isU8a, u8aConcat, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import { Codec, Constructor, ConstructorDef } from '../types';
|
||||
import decodeU8a from './utils/decodeU8a';
|
||||
import { compareMap, decodeU8a } from './utils';
|
||||
|
||||
/**
|
||||
* @name Struct
|
||||
@@ -152,6 +152,13 @@ export default class Struct<
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return compareMap(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns a specific names entry in the structure
|
||||
* @param name The name of the entry to retrieve
|
||||
|
||||
@@ -85,4 +85,13 @@ describe('Tuple', () => {
|
||||
expect(tuple.map(v => v.toString())).toEqual(['bazzing', '69']);
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares against inputs', () => {
|
||||
expect(tuple.eq(['bazzing', 69])).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against inputs (mismatch)', () => {
|
||||
expect(tuple.eq(['bazzing', 72])).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { isU8a, u8aConcat, u8aToHex, isHex, hexToU8a } from '@polkadot/util';
|
||||
|
||||
import { AnyNumber, AnyU8a, AnyString, Codec, Constructor } from '../types';
|
||||
import decodeU8a from './utils/decodeU8a';
|
||||
import { compareArray, decodeU8a } from './utils';
|
||||
|
||||
type TupleConstructors = Array<Constructor> | {
|
||||
[index: string]: Constructor
|
||||
@@ -71,6 +71,13 @@ export default class Tuple extends Array<Codec> implements Codec {
|
||||
: Object.keys(this._Types);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return compareArray(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Converts the Object to an standard JavaScript Array
|
||||
*/
|
||||
|
||||
@@ -51,4 +51,22 @@ describe('U8a', () => {
|
||||
it('implements subarray correctly', () => {
|
||||
expect(u8a.subarray(1, 3)).toEqual(Uint8Array.from([2, 3]));
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
it('compares against other U8a', () => {
|
||||
expect(u8a.eq(new Uint8Array([1, 2, 3, 4, 5]))).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against other U8a (non-length)', () => {
|
||||
expect(u8a.eq(new Uint8Array([1, 2, 3, 4]))).toBe(false);
|
||||
});
|
||||
|
||||
it('compares against other U8a (mismatch)', () => {
|
||||
expect(u8a.eq(new Uint8Array([1, 2, 3, 4, 6]))).toBe(false);
|
||||
});
|
||||
|
||||
it('compares against hex inputs', () => {
|
||||
expect(u8a.eq('0x0102030405')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -52,6 +52,19 @@ export default class U8a extends Uint8Array implements Codec {
|
||||
return super.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
if (other instanceof Uint8Array) {
|
||||
return (this.length === other.length) && isUndefined(
|
||||
this.find((value, index) => value !== other[index])
|
||||
);
|
||||
}
|
||||
|
||||
return this.eq(U8a.decodeU8a(other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Create a new subarray from the actual buffer. This is needed for compat reasons since a new Uint8Array gets returned here
|
||||
* @param begin The position to start at
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
||||
import UInt from './UInt';
|
||||
|
||||
describe('UInt', () => {
|
||||
@@ -48,4 +50,20 @@ describe('UInt', () => {
|
||||
expect(new UInt(0x12, 16).toJSON()).toEqual('0x0012');
|
||||
expect(new UInt(0x12, 16, false).toJSON()).toEqual(0x12);
|
||||
});
|
||||
|
||||
describe('eq', () => {
|
||||
const test = new UInt(12345);
|
||||
|
||||
it('compares against other BN values', () => {
|
||||
expect(test.eq(new BN(12345))).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against other number values', () => {
|
||||
expect(test.eq(12345)).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against hex values', () => {
|
||||
expect(test.eq('0x3039')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -116,4 +116,16 @@ describe('Vector', () => {
|
||||
testEncode('toString', '[1, 23, 345, 4567, 56789]');
|
||||
testEncode('toU8a', Uint8Array.from([20, 4, 49, 8, 50, 51, 12, 51, 52, 53, 16, 52, 53, 54, 55, 20, 53, 54, 55, 56, 57]));
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
const vec = new Vector(Text, ['123', '456']);
|
||||
|
||||
it('compares against codec types', () => {
|
||||
expect(vec.eq([new Text('123'), new Text('456')])).toBe(true);
|
||||
});
|
||||
|
||||
it('compares against codec + primitive types', () => {
|
||||
expect(vec.eq(['123', new Text('456')])).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,12 +6,12 @@ import { u8aConcat, u8aToU8a, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import Compact from './Compact';
|
||||
import { Codec, Constructor } from '../types';
|
||||
import decodeU8a from './utils/decodeU8a';
|
||||
import { compareArray, decodeU8a } from './utils';
|
||||
|
||||
/**
|
||||
* @name Vector
|
||||
* @description
|
||||
* This manages codec arrays. Intrernally it keeps track of the length (as decoded) and allows
|
||||
* This manages codec arrays. Internally it keeps track of the length (as decoded) and allows
|
||||
* construction with the passed `Type` in the constructor. It is an extension to Array, providing
|
||||
* specific encoding/decoding on top of the base type.
|
||||
* @noInheritDoc
|
||||
@@ -75,6 +75,13 @@ export default class Vector<
|
||||
return super.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean {
|
||||
return compareArray(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Converts the Object to an standard JavaScript Array
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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 U32 from '../../U32';
|
||||
import compareArray from './compareArray';
|
||||
|
||||
describe('compareArray', () => {
|
||||
const a = [new U32(123), new U32(456), new U32(789)];
|
||||
|
||||
it('returns false when second param is a non-array', () => {
|
||||
expect(
|
||||
compareArray(a, 123)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('compares array of codec agains primitive', () => {
|
||||
expect(
|
||||
compareArray(a, [123, 456, 789])
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares array of codec agains codec', () => {
|
||||
expect(
|
||||
compareArray(a, [new U32(123), new U32(456), new U32(789)])
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares primitive against primitive', () => {
|
||||
expect(
|
||||
compareArray(
|
||||
[123, 456], [123, 456]
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when lengths are not matching', () => {
|
||||
expect(
|
||||
compareArray(a, [123])
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when value mismatches', () => {
|
||||
expect(
|
||||
compareArray(a, [123, 456, 999])
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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 { isFunction, isUndefined } from '@polkadot/util';
|
||||
|
||||
// NOTE These are used internally and when comparing objects, expects that
|
||||
// when the second is an Array<Codec> that the first has to be as well
|
||||
export default function compareArray (a: Array<any>, b?: any): boolean {
|
||||
if (Array.isArray(b)) {
|
||||
return (a.length === b.length) && isUndefined(
|
||||
a.find((value, index) =>
|
||||
isFunction(value.eq)
|
||||
? !value.eq(b[index])
|
||||
: value !== b[index]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// 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 { Codec } from '../../types';
|
||||
import U32 from '../../U32';
|
||||
import compareMap from './compareMap';
|
||||
|
||||
describe('compareMap', () => {
|
||||
const a = new Map<string, Codec>([
|
||||
['decimals', new U32(15)],
|
||||
['missing', new U32(10)],
|
||||
['foobar', new U32(5)]
|
||||
]);
|
||||
const b = new Map<string, any>([
|
||||
['decimals', 15],
|
||||
['missing', 10],
|
||||
['foobar', 5]
|
||||
]);
|
||||
const c = new Map<string, Codec>([
|
||||
['decimals', new U32(15)],
|
||||
['missing', new U32(10)],
|
||||
['foobar', new U32(5)]
|
||||
]);
|
||||
|
||||
it('compares Map<string, Codec> against Object', () => {
|
||||
expect(
|
||||
compareMap(a, {
|
||||
decimals: 15,
|
||||
foobar: 5,
|
||||
missing: 10
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares Map<string, any> against entries array', () => {
|
||||
expect(
|
||||
compareMap(b, [
|
||||
['missing', 10], ['decimals', 15], ['foobar', 5]
|
||||
])
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('compares between 2 maps', () => {
|
||||
expect(compareMap(a, b)).toBe(true);
|
||||
});
|
||||
|
||||
it('compares between 2 maps (both codec)', () => {
|
||||
expect(compareMap(a, c)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when second param is a non-map, non-array, non-object', () => {
|
||||
expect(
|
||||
compareMap(a, 123)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when second param is a array with non-entries', () => {
|
||||
expect(
|
||||
compareMap(a, [123, 456, 789])
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when second param is a array with non-entries (only key)', () => {
|
||||
expect(
|
||||
compareMap(a, [[123], [456], [789]])
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when properties are missing', () => {
|
||||
expect(
|
||||
compareMap(a, [['decimals', 15], ['wrong', 10], ['foobar', 5]])
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when lengths do not match', () => {
|
||||
expect(
|
||||
compareMap(a, [['decimals', 15]])
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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 { isFunction, isObject, isUndefined } from '@polkadot/util';
|
||||
|
||||
// NOTE These are used internally and when comparing objects, expects that
|
||||
// when the second is an Map<string, Codec> that the first has to be as well
|
||||
export default function compareMap (a: Map<any, any>, b?: any): boolean {
|
||||
if (Array.isArray(b)) {
|
||||
return (a.size === b.length) && isUndefined(
|
||||
b.find((entry) => {
|
||||
if (!Array.isArray(entry) || entry.length !== 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const value = a.get(entry[0]);
|
||||
|
||||
return isUndefined(value) || (
|
||||
// Codec has .eq, use it here
|
||||
isFunction(value.eq)
|
||||
? !value.eq(entry[1])
|
||||
: value !== entry[1]
|
||||
);
|
||||
})
|
||||
);
|
||||
} else if (b instanceof Map) {
|
||||
return compareMap(a, [...b.entries()]);
|
||||
} else if (isObject(b)) {
|
||||
return compareMap(a, Object.entries(b));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 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.
|
||||
|
||||
export { default as compareArray } from './compareArray';
|
||||
export { default as compareMap } from './compareMap';
|
||||
export { default as decodeU8a } from './decodeU8a';
|
||||
@@ -23,6 +23,11 @@ export interface Codec {
|
||||
*/
|
||||
encodedLength: number;
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
eq (other?: any): boolean;
|
||||
|
||||
/**
|
||||
* @description Returns a hex string representation of the value
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user