diff --git a/packages/bignumber/src.ts/bignumber.ts b/packages/bignumber/src.ts/bignumber.ts index 2955249d3c..8bf9197a35 100644 --- a/packages/bignumber/src.ts/bignumber.ts +++ b/packages/bignumber/src.ts/bignumber.ts @@ -202,7 +202,7 @@ export class BigNumber implements Hexable { if (value instanceof BigNumber) { return value; } if (typeof(value) === "string") { - if (value.match(/-?0x[0-9a-f]+/i)) { + if (value.match(/^-?0x[0-9a-f]+$/i)) { return new BigNumber(_constructorGuard, toHex(value)); } diff --git a/packages/testcases/ingest.js b/packages/testcases/ingest.js new file mode 100644 index 0000000000..5b9e4bc63a --- /dev/null +++ b/packages/testcases/ingest.js @@ -0,0 +1,13 @@ +"use strict"; + +const fs = require("fs"); +const { resolve } = require("path"); + +const { saveTests } = require("./lib/index"); + +function ingest(tag) { + const data = JSON.parse(fs.readFileSync(resolve(__dirname, "input", tag + ".json")).toString()); + saveTests(tag, data); +} + +ingest("bignumber") diff --git a/packages/testcases/input/bignumber.json b/packages/testcases/input/bignumber.json new file mode 100644 index 0000000000..f5f353373d --- /dev/null +++ b/packages/testcases/input/bignumber.json @@ -0,0 +1,187 @@ +[ + { + "testcase": "HexStrings - Zero; odd-length", + "value": "0x0", + "expectedValue": "0x00" + }, + { + "testcase": "HexStrings - Zero; padded", + "value": "0x00", + "expectedValue": "0x00" + }, + { + "testcase": "HexStrings - Negative Zero", + "value": "-0x00", + "expectedValue": "0x00" + }, + { + "testcase": "HexStrings - One", + "value": "0x1", + "expectedValue": "0x01" + }, + { + "testcase": "HexStrings - Negative One", + "value": "-0x1", + "expectedValue": "-0x01" + }, + { + "testcase": "HexStrings - Over 32-bits", + "value": "0xdeadbeef1", + "expectedValue": "0x0deadbeef1" + }, + { + "testcase": "HexStrings - Over 32-bits (negative)", + "value": "-0xdeadbeef1", + "expectedValue": "-0x0deadbeef1" + }, + { + "testcase": "HexStrings - Over 53-bits", + "value": "0xfffffffffffffff", + "expectedValue": "0x0fffffffffffffff" + }, + { + "testcase": "HexStrings - Over 53-bits (negative)", + "value": "-0xfffffffffffffff", + "expectedValue": "-0x0fffffffffffffff" + }, + { + "testcase": "HexStrings - Over 64-bits", + "value": "0xdeadbeefdeadbeef1", + "expectedValue": "0x0deadbeefdeadbeef1" + }, + { + "testcase": "HexStrings - Over 64-bits (negative)", + "value": "-0xdeadbeefdeadbeef1", + "expectedValue": "-0x0deadbeefdeadbeef1" + }, + { + "testcase": "DecimalStrings - Zero", + "value": "0", + "expectedValue": "0x00" + }, + { + "testcase": "DecimalStrings - One", + "value": "1", + "expectedValue": "0x01" + }, + { + "testcase": "DecimalStrings - Negative One", + "value": "-1", + "expectedValue": "-0x01" + }, + { + "testcase": "DecimalStrings - Life and such", + "value": "42", + "expectedValue": "0x2a" + }, + { + "testcase": "DecimalStrings - Life and such (negative)", + "value": "-42", + "expectedValue": "-0x2a" + }, + { + "testcase": "DecimalStrings - MAX_SAFE_INTEGER", + "value": "9007199254740991", + "expectedValue": "0x1fffffffffffff" + }, + { + "testcase": "DecimalStrings - MAX_SAFE_INTEGER (negative)", + "value": "-9007199254740991", + "expectedValue": "-0x1fffffffffffff" + }, + { + "testcase": "DecimalStrings - High value not on compact boundary", + "value": "9007199254740995", + "expectedValue": "0x20000000000003" + }, + { + "testcase": "DecimalStrings - Low value not on compact boundary", + "value": "-9007199254740995", + "expectedValue": "-0x20000000000003" + }, + { + "testcase": "Numbers - Zero", + "value": 0, + "expectedValue": "0x00" + }, + { + "testcase": "Numbers - One", + "value": 1, + "expectedValue": "0x01" + }, + { + "testcase": "Numbers - Negative One", + "value": -1, + "expectedValue": "-0x01" + }, + { + "testcase": "Numbers - BigNumber Safe", + "value": 9007199254740990, + "expectedValue": "0x1ffffffffffffe" + }, + { + "testcase": "Numbers - BigNumber Safe (negative)", + "value": -9007199254740990, + "expectedValue": "-0x1ffffffffffffe" + }, + { + "testcase": "Invalid - Empty value", + "value": "0x", + "expectedValue": null + }, + { + "testcase": "Invalid - The x of 0x0", + "value": "x", + "expectedValue": null + }, + { + "testcase": "Invalid - Negative at the end", + "value": "0123-", + "expectedValue": null + }, + { + "testcase": "Invalid - Negative in middle", + "value": "0123-456", + "expectedValue": null + }, + { + "testcase": "Invalid - Double negative", + "value": "--123", + "expectedValue": null + }, + { + "testcase": "Invalid - MAX_SAFE_INTEGER", + "value": 9007199254740991, + "expectedValue": null + }, + { + "testcase": "Invalid - -MAX_SAFE_INTEGER", + "value": -9007199254740991, + "expectedValue": null + }, + { + "testcase": "Invalid - Too high; safe value", + "value": 9007199254740996, + "expectedValue": null + }, + { + "testcase": "Invalid - Too low; save value", + "value": -9007199254740996, + "expectedValue": null + }, + { + "testcase": "Invalid - Random text", + "value": "hello world", + "expectedValue": null + }, + { + "testcase": "Invalid - Bad hex character", + "value": "0x123g", + "expectedValue": null + }, + { + "testcase": "Invalid - See #935", + "value": "0-0x1 whatever", + "expectedValue": null + } +] diff --git a/packages/testcases/src.ts/index.ts b/packages/testcases/src.ts/index.ts index 2b1134d2dd..86e17f1ebf 100644 --- a/packages/testcases/src.ts/index.ts +++ b/packages/testcases/src.ts/index.ts @@ -8,6 +8,12 @@ import { randomBytes, randomHexString, randomNumber } from "./random"; export { randomBytes, randomHexString, randomNumber }; export module TestCase { + export type BigNumber = { + testcase: string; + value: string | number; + expectedValue: string; + }; + export type HDWalletNode = { path: string; address: string; diff --git a/packages/testcases/testcases/bignumber.json.gz b/packages/testcases/testcases/bignumber.json.gz new file mode 100644 index 0000000000..bc5a94ab93 Binary files /dev/null and b/packages/testcases/testcases/bignumber.json.gz differ diff --git a/packages/tests/src.ts/test-utils.ts b/packages/tests/src.ts/test-utils.ts index cc98750443..ef7c5ed3c1 100644 --- a/packages/tests/src.ts/test-utils.ts +++ b/packages/tests/src.ts/test-utils.ts @@ -441,26 +441,6 @@ describe('Test Bytes32String coder', function() { }); }); -describe('Test BigNumber', function() { - it("computes absolute values", function() { - function testAbs(test: { expected: string, value: string }) { - let value = ethers.BigNumber.from(test.value); - let expected = ethers.BigNumber.from(test.expected); - assert.ok(value.abs().eq(expected), 'BigNumber.abs - ' + test.value); - } - - [ - { value: "0x0", expected: "0x0" }, - { value: "-0x0", expected: "0x0" }, - { value: "0x5", expected: "0x5" }, - { value: "-0x5", expected: "0x5" }, - { value: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, - { value: "-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, - { value: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, - { value: "-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, - ].forEach(testAbs); - }); -}); function getHex(value: string): string { return "0x" + Buffer.from(value).toString("hex"); @@ -537,3 +517,47 @@ describe("Test Signature Manipulation", function() { }); }); }); + +describe("BigNumber", function() { + const tests: Array = loadTests("bignumber"); + tests.forEach((test) => { + if (test.expectedValue == null) { + it(test.testcase, function() { + assert.throws(() => { + const value = ethers.BigNumber.from(test.value); + console.log("ERROR", value); + }, (error: Error) => { + return true; + }); + }); + } else { + it(test.testcase, function() { + const value = ethers.BigNumber.from(test.value); + assert.equal(value.toHexString(), test.expectedValue); + + const value2 = ethers.BigNumber.from(value) + assert.equal(value2.toHexString(), test.expectedValue); + }); + } + }); + + [ + { value: "0x0", expected: "0x0" }, + { value: "-0x0", expected: "0x0" }, + { value: "0x5", expected: "0x5" }, + { value: "-0x5", expected: "0x5" }, + { value: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + { value: "-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + { value: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + { value: "-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + ].forEach((test) => { + it(`absolute value (${ test.value })`, function() { + const value = ethers.BigNumber.from(test.value); + const expected = ethers.BigNumber.from(test.expected); + assert.ok(value.abs().eq(expected)); + }); + }); + + // @TODO: Add more tests here + +});