Commit ad94b9d1 authored by Johns's avatar Johns

test/docs: Improve docstrings and tests for utils in hex-strings.ts

parent d14ee9fa
---
'@eth-optimism/core-utils': patch
---
test/docs: Improve docstrings and tests for utils inside of hex-strings.ts
...@@ -56,6 +56,12 @@ export const toHexString = (inp: Buffer | string | number | null): string => { ...@@ -56,6 +56,12 @@ export const toHexString = (inp: Buffer | string | number | null): string => {
} }
} }
/**
* Casts a number to a hex string without zero padding.
*
* @param n Number to cast to a hex string.
* @return Number cast as a hex string.
*/
export const toRpcHexString = (n: number | BigNumber): string => { export const toRpcHexString = (n: number | BigNumber): string => {
let num let num
if (typeof n === 'number') { if (typeof n === 'number') {
...@@ -67,10 +73,18 @@ export const toRpcHexString = (n: number | BigNumber): string => { ...@@ -67,10 +73,18 @@ export const toRpcHexString = (n: number | BigNumber): string => {
if (num === '0x0') { if (num === '0x0') {
return num return num
} else { } else {
// BigNumber pads a single 0 to keep hex length even
return num.replace(/^0x0/, '0x') return num.replace(/^0x0/, '0x')
} }
} }
/**
* Zero pads a hex string if str.length !== 2 + length * 2. Pads to length * 2.
*
* @param str Hex string to pad
* @param length Half the length of the desired padded hex string
* @return Hex string with length of 2 + length * 2
*/
export const padHexString = (str: string, length: number): string => { export const padHexString = (str: string, length: number): string => {
if (str.length === 2 + length * 2) { if (str.length === 2 + length * 2) {
return str return str
...@@ -79,9 +93,25 @@ export const padHexString = (str: string, length: number): string => { ...@@ -79,9 +93,25 @@ export const padHexString = (str: string, length: number): string => {
} }
} }
export const encodeHex = (val: any, len: number) => /**
* Casts an input to hex string without '0x' prefix with conditional padding.
* Hex string will always start with a 0.
*
* @param val Input to cast to a hex string.
* @param len Desired length to pad hex string. Ignored if less than hex string length.
* @return Hex string with '0' prefix
*/
export const encodeHex = (val: any, len: number): string =>
remove0x(BigNumber.from(val).toHexString()).padStart(len, '0') remove0x(BigNumber.from(val).toHexString()).padStart(len, '0')
/**
* Case insensitive hex string equality check
*
* @param stringA Hex string A
* @param stringB Hex string B
* @throws {Error} Inputs must be valid hex strings
* @return True if equal
*/
export const hexStringEquals = (stringA: string, stringB: string): boolean => { export const hexStringEquals = (stringA: string, stringB: string): boolean => {
if (!ethers.utils.isHexString(stringA)) { if (!ethers.utils.isHexString(stringA)) {
throw new Error(`input is not a hex string: ${stringA}`) throw new Error(`input is not a hex string: ${stringA}`)
...@@ -94,6 +124,12 @@ export const hexStringEquals = (stringA: string, stringB: string): boolean => { ...@@ -94,6 +124,12 @@ export const hexStringEquals = (stringA: string, stringB: string): boolean => {
return stringA.toLowerCase() === stringB.toLowerCase() return stringA.toLowerCase() === stringB.toLowerCase()
} }
/**
* Casts a number to a 32-byte, zero padded hex string.
*
* @param value Number to cast to a hex string.
* @return Number cast as a hex string.
*/
export const bytes32ify = (value: number | BigNumber): string => { export const bytes32ify = (value: number | BigNumber): string => {
return hexZeroPad(BigNumber.from(value).toHexString(), 32) return hexZeroPad(BigNumber.from(value).toHexString(), 32)
} }
...@@ -9,6 +9,9 @@ import { ...@@ -9,6 +9,9 @@ import {
fromHexString, fromHexString,
toHexString, toHexString,
padHexString, padHexString,
encodeHex,
hexStringEquals,
bytes32ify,
} from '../src' } from '../src'
describe('remove0x', () => { describe('remove0x', () => {
...@@ -52,13 +55,17 @@ describe('add0x', () => { ...@@ -52,13 +55,17 @@ describe('add0x', () => {
}) })
describe('toHexString', () => { describe('toHexString', () => {
it('should return undefined', () => { it('should throw an error when input is null', () => {
expect(add0x(undefined)).to.deep.equal(undefined) expect(() => {
toHexString(null)
}).to.throw(
'The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received null'
)
}) })
it('should return with a hex string', () => { it('should return with a hex string', () => {
const cases = [ const cases = [
{ input: 0, output: '0x00' }, { input: 0, output: '0x00' },
{ input: 48, output: '0x30' },
{ {
input: '0', input: '0',
output: '0x30', output: '0x30',
...@@ -122,3 +129,184 @@ describe('toRpcHexString', () => { ...@@ -122,3 +129,184 @@ describe('toRpcHexString', () => {
} }
}) })
}) })
describe('encodeHex', () => {
it('should throw an error when val is invalid', () => {
expect(() => {
encodeHex(null, 0)
}).to.throw('invalid BigNumber value')
expect(() => {
encodeHex(10.5, 0)
}).to.throw('fault="underflow", operation="BigNumber.from", value=10.5')
expect(() => {
encodeHex('10.5', 0)
}).to.throw('invalid BigNumber string')
})
it('should return a hex string of val with length len', () => {
const cases = [
{
input: {
val: 0,
len: 0,
},
output: '00',
},
{
input: {
val: 0,
len: 4,
},
output: '0000',
},
{
input: {
val: 1,
len: 0,
},
output: '01',
},
{
input: {
val: 1,
len: 10,
},
output: '0000000001',
},
{
input: {
val: 100,
len: 4,
},
output: '0064',
},
{
input: {
val: '100',
len: 0,
},
output: '64',
},
]
for (const test of cases) {
expect(encodeHex(test.input.val, test.input.len)).to.deep.equal(
test.output
)
}
})
})
describe('hexStringEquals', () => {
it('should throw an error when input is not a hex string', () => {
expect(() => {
hexStringEquals('', '')
}).to.throw('input is not a hex string: ')
expect(() => {
hexStringEquals('0xx', '0x1')
}).to.throw('input is not a hex string: 0xx')
expect(() => {
hexStringEquals('0x1', '2')
}).to.throw('input is not a hex string: 2')
expect(() => {
hexStringEquals('-0x1', '0x1')
}).to.throw('input is not a hex string: -0x1')
})
it('should return the hex strings equality', () => {
const cases = [
{
input: {
stringA: '0x',
stringB: '0x',
},
output: true,
},
{
input: {
stringA: '0x1',
stringB: '0x1',
},
output: true,
},
{
input: {
stringA: '0x064',
stringB: '0x064',
},
output: true,
},
{
input: {
stringA: '0x',
stringB: '0x0',
},
output: false,
},
{
input: {
stringA: '0x0',
stringB: '0x1',
},
output: false,
},
{
input: {
stringA: '0x64',
stringB: '0x064',
},
output: false,
},
]
for (const test of cases) {
expect(
hexStringEquals(test.input.stringA, test.input.stringB)
).to.deep.equal(test.output)
}
})
})
describe('bytes32ify', () => {
it('should throw an error when input is invalid', () => {
expect(() => {
bytes32ify(-1)
}).to.throw('invalid hex string')
})
it('should return a zero padded, 32 bytes hex string', () => {
const cases = [
{
input: 0,
output:
'0x0000000000000000000000000000000000000000000000000000000000000000',
},
{
input: BigNumber.from(0),
output:
'0x0000000000000000000000000000000000000000000000000000000000000000',
},
{
input: 2,
output:
'0x0000000000000000000000000000000000000000000000000000000000000002',
},
{
input: BigNumber.from(2),
output:
'0x0000000000000000000000000000000000000000000000000000000000000002',
},
{
input: 100,
output:
'0x0000000000000000000000000000000000000000000000000000000000000064',
},
]
for (const test of cases) {
expect(bytes32ify(test.input)).to.deep.equal(test.output)
}
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment