@0x/contracts-test-utils: Add number_utils.ts and hexSize().
				
					
				
			This commit is contained in:
		| @@ -93,6 +93,10 @@ | |||||||
|             { |             { | ||||||
|                 "note": "Add `shortZip()` to `lang_utils.ts`", |                 "note": "Add `shortZip()` to `lang_utils.ts`", | ||||||
|                 "pr": 2155 |                 "pr": 2155 | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 "note": "Add `number_utils.ts` and `hexSize()`", | ||||||
|  |                 "pr": "TODO" | ||||||
|             } |             } | ||||||
|         ] |         ] | ||||||
|     }, |     }, | ||||||
|   | |||||||
| @@ -65,6 +65,13 @@ export function hexHash(n: Numberish): string { | |||||||
|     return ethUtil.bufferToHex(ethUtil.sha3(ethUtil.toBuffer(toHex(n)))); |     return ethUtil.bufferToHex(ethUtil.sha3(ethUtil.toBuffer(toHex(n)))); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Get the length, in bytes, of a hex string. | ||||||
|  |  */ | ||||||
|  | export function hexSize(hex: string): number { | ||||||
|  |     return Math.ceil((hex.length - 2) / 2); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Convert a string, a number, or a BigNumber into a hex string. |  * Convert a string, a number, or a BigNumber into a hex string. | ||||||
|  * Works with negative numbers, as well. |  * Works with negative numbers, as well. | ||||||
|   | |||||||
| @@ -28,7 +28,17 @@ export { bytes32Values, testCombinatoriallyWithReferenceFunc, uint256Values } fr | |||||||
| export { TransactionFactory } from './transaction_factory'; | export { TransactionFactory } from './transaction_factory'; | ||||||
| export { MutatorContractFunction, TransactionHelper } from './transaction_helper'; | export { MutatorContractFunction, TransactionHelper } from './transaction_helper'; | ||||||
| export { testWithReferenceFuncAsync } from './test_with_reference'; | export { testWithReferenceFuncAsync } from './test_with_reference'; | ||||||
| export { hexConcat, hexHash, hexLeftPad, hexInvert, hexSlice, hexRandom, hexRightPad, toHex } from './hex_utils'; | export { | ||||||
|  |     hexConcat, | ||||||
|  |     hexHash, | ||||||
|  |     hexLeftPad, | ||||||
|  |     hexInvert, | ||||||
|  |     hexSlice, | ||||||
|  |     hexRandom, | ||||||
|  |     hexRightPad, | ||||||
|  |     hexSize, | ||||||
|  |     toHex, | ||||||
|  | } from './hex_utils'; | ||||||
| export { | export { | ||||||
|     BatchMatchOrder, |     BatchMatchOrder, | ||||||
|     ContractName, |     ContractName, | ||||||
| @@ -51,3 +61,12 @@ export { blockchainTests, BlockchainTestsEnvironment, describe } from './mocha_b | |||||||
| export { chaiSetup, expect } from './chai_setup'; | export { chaiSetup, expect } from './chai_setup'; | ||||||
| export { getCodesizeFromArtifact } from './codesize'; | export { getCodesizeFromArtifact } from './codesize'; | ||||||
| export { shortZip } from './lang_utils'; | export { shortZip } from './lang_utils'; | ||||||
|  | export { | ||||||
|  |     assertIntegerRoughlyEquals, | ||||||
|  |     assertRoughlyEquals, | ||||||
|  |     getRandomFloat, | ||||||
|  |     getRandomInteger, | ||||||
|  |     getRandomPortion, | ||||||
|  |     getNumericalDivergence, | ||||||
|  |     toBaseUnitAmount, | ||||||
|  | } from './number_utils'; | ||||||
|   | |||||||
							
								
								
									
										88
									
								
								contracts/test-utils/src/number_utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								contracts/test-utils/src/number_utils.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | |||||||
|  | import { BigNumber } from '@0x/utils'; | ||||||
|  | import { Web3Wrapper } from '@0x/web3-wrapper'; | ||||||
|  | import * as crypto from 'crypto'; | ||||||
|  |  | ||||||
|  | import { expect } from './chai_setup'; | ||||||
|  | import { Numberish } from './types'; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Generate a random integer between `min` and `max`, inclusive. | ||||||
|  |  */ | ||||||
|  | export function getRandomInteger(min: Numberish, max: Numberish): BigNumber { | ||||||
|  |     const range = new BigNumber(max).minus(min); | ||||||
|  |     return getRandomPortion(range).plus(min); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Generate a random integer between `0` and `total`, inclusive. | ||||||
|  |  */ | ||||||
|  | export function getRandomPortion(total: Numberish): BigNumber { | ||||||
|  |     return new BigNumber(total).times(getRandomFloat(0, 1)).integerValue(BigNumber.ROUND_HALF_UP); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Generate a random, high-precision decimal between `min` and `max`, inclusive. | ||||||
|  |  */ | ||||||
|  | export function getRandomFloat(min: Numberish, max: Numberish): BigNumber { | ||||||
|  |     // Generate a really high precision number between [0, 1] | ||||||
|  |     const r = new BigNumber(crypto.randomBytes(32).toString('hex'), 16).dividedBy(new BigNumber(2).pow(256).minus(1)); | ||||||
|  |     return new BigNumber(max) | ||||||
|  |         .minus(min) | ||||||
|  |         .times(r) | ||||||
|  |         .plus(min); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Converts two decimal numbers to integers with `precision` digits, then returns | ||||||
|  |  * the absolute difference. | ||||||
|  |  */ | ||||||
|  | export function getNumericalDivergence(a: Numberish, b: Numberish, precision: number = 18): number { | ||||||
|  |     const _a = new BigNumber(a); | ||||||
|  |     const _b = new BigNumber(b); | ||||||
|  |     const maxIntegerDigits = Math.max( | ||||||
|  |         _a.integerValue(BigNumber.ROUND_DOWN).sd(true), | ||||||
|  |         _b.integerValue(BigNumber.ROUND_DOWN).sd(true), | ||||||
|  |     ); | ||||||
|  |     const _toInteger = (n: BigNumber) => { | ||||||
|  |         const base = 10 ** (precision - maxIntegerDigits); | ||||||
|  |         return n.times(base).integerValue(BigNumber.ROUND_DOWN); | ||||||
|  |     }; | ||||||
|  |     return _toInteger(_a) | ||||||
|  |         .minus(_toInteger(_b)) | ||||||
|  |         .abs() | ||||||
|  |         .toNumber(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Asserts that two numbers are equal up to `precision` digits. | ||||||
|  |  */ | ||||||
|  | export function assertRoughlyEquals(actual: Numberish, expected: Numberish, precision: number = 18): void { | ||||||
|  |     if (getNumericalDivergence(actual, expected, precision) <= 1) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     expect(actual).to.bignumber.eq(expected); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Asserts that two numbers are equal with up to `maxError` difference between them. | ||||||
|  |  */ | ||||||
|  | export function assertIntegerRoughlyEquals(actual: Numberish, expected: Numberish, maxError: number = 1): void { | ||||||
|  |     const diff = new BigNumber(actual) | ||||||
|  |         .minus(expected) | ||||||
|  |         .abs() | ||||||
|  |         .toNumber(); | ||||||
|  |     if (diff <= maxError) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     expect(actual).to.bignumber.eq(expected); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Converts `amount` into a base unit amount with 18 digits. | ||||||
|  |  */ | ||||||
|  | export function toBaseUnitAmount(amount: Numberish): BigNumber { | ||||||
|  |     const decimals = 18; | ||||||
|  |     const amountAsBigNumber = new BigNumber(amount); | ||||||
|  |     const baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amountAsBigNumber, decimals); | ||||||
|  |     return baseUnitAmount; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user