Added tests to help fill out coverage tests.
This commit is contained in:
parent
79b1da130b
commit
1cfe4962aa
@ -141,3 +141,94 @@ describe('Test HD Mnemonic Phrases', function testMnemonic() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("HD Extended Keys", function() {
|
||||
const root = ethers.utils.HDNode.fromSeed("0xdeadbeefdeadbeefdeadbeefdeadbeef");
|
||||
const root42 = root.derivePath("42");
|
||||
|
||||
it("exports and imports xpriv extended keys", function() {
|
||||
const xpriv = root.extendedKey;
|
||||
const node = ethers.utils.HDNode.fromExtendedKey(xpriv);
|
||||
|
||||
assert.equal(root.address, node.address, "address matches");
|
||||
|
||||
const node42 = node.derivePath("42");
|
||||
assert.equal(root42.address, node42.address, "address matches");
|
||||
});
|
||||
|
||||
it("exports and imports xpub extended keys", function() {
|
||||
const xpub = root.neuter().extendedKey;
|
||||
const node = ethers.utils.HDNode.fromExtendedKey(xpub);
|
||||
|
||||
assert.equal(root.address, node.address, "address matches");
|
||||
|
||||
const node42 = node.derivePath("42");
|
||||
assert.equal(root42.address, node42.address, "address matches");
|
||||
});
|
||||
});
|
||||
|
||||
describe("HD error cases", function() {
|
||||
const testInvalid = [
|
||||
"",
|
||||
"m/45/m",
|
||||
"m/44/foobar"
|
||||
];
|
||||
|
||||
const root = ethers.utils.HDNode.fromSeed("0xdeadbeefdeadbeefdeadbeefdeadbeef");
|
||||
|
||||
testInvalid.forEach((path) => {
|
||||
it(`fails on path "${ path }"`, function() {
|
||||
assert.throws(() => {
|
||||
root.derivePath(path);
|
||||
}, (error: any) => {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("fails to derive child of hardened key", function() {
|
||||
// Deriving non-hardened should work...
|
||||
const node = root.neuter().derivePath("44");
|
||||
|
||||
assert.throws(() => {
|
||||
// Deriving hardened should fail...
|
||||
node.derivePath("44'");
|
||||
}, (error: any) => {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
// The zero-mnemonic, with and without correct checksum
|
||||
const zeroMnemonicCS = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
||||
const zeroMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon";
|
||||
|
||||
it("fails on invalid mnemonic length", function() {
|
||||
const shortMnemonic = "abandon abandon abandon abandon";
|
||||
|
||||
// Test the validate functions
|
||||
assert.ok(ethers.utils.isValidMnemonic(zeroMnemonicCS));
|
||||
assert.ok(!ethers.utils.isValidMnemonic(zeroMnemonic));
|
||||
assert.ok(!ethers.utils.isValidMnemonic(shortMnemonic));
|
||||
|
||||
assert.throws(() => {
|
||||
ethers.utils.mnemonicToEntropy(shortMnemonic);
|
||||
}, (error: any) => {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
it("fails on invalid checksum", function() {
|
||||
assert.throws(() => {
|
||||
ethers.utils.mnemonicToEntropy(zeroMnemonic);
|
||||
}, (error: any) => {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
it("fails on unknown locale", function() {
|
||||
assert.throws(() => {
|
||||
ethers.utils.HDNode.fromMnemonic(zeroMnemonicCS, "foobar", "xx");
|
||||
}, (error: any) => {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -664,3 +664,113 @@ describe("Test Basic Authentication", function() {
|
||||
}, "throws an exception for insecure connections");
|
||||
})
|
||||
});
|
||||
|
||||
describe("Test API Key Formatting", function() {
|
||||
it("Infura API Key", function() {
|
||||
const projectId = "someProjectId";
|
||||
const projectSecret = "someSecretKey";
|
||||
|
||||
// Test simple projectId
|
||||
const apiKeyString = ethers.providers.InfuraProvider.getApiKey(projectId);
|
||||
assert.equal(apiKeyString.apiKey, projectId);
|
||||
assert.equal(apiKeyString.projectId, projectId);
|
||||
assert.ok(apiKeyString.secretKey == null);
|
||||
|
||||
// Test complex API key with projectId
|
||||
const apiKeyObject = ethers.providers.InfuraProvider.getApiKey({
|
||||
projectId
|
||||
});
|
||||
assert.equal(apiKeyObject.apiKey, projectId);
|
||||
assert.equal(apiKeyObject.projectId, projectId);
|
||||
assert.ok(apiKeyObject.projectSecret == null);
|
||||
|
||||
// Test complex API key with projectId and projectSecret
|
||||
const apiKeyObject2 = ethers.providers.InfuraProvider.getApiKey({
|
||||
projectId: projectId,
|
||||
projectSecret: projectSecret
|
||||
});
|
||||
assert.equal(apiKeyObject2.apiKey, projectId);
|
||||
assert.equal(apiKeyObject2.projectId, projectId);
|
||||
assert.equal(apiKeyObject2.projectSecret, projectSecret);
|
||||
|
||||
// Fails on invalid projectId type
|
||||
assert.throws(() => {
|
||||
const apiKey = ethers.providers.InfuraProvider.getApiKey({
|
||||
projectId: 1234,
|
||||
projectSecret: projectSecret
|
||||
});
|
||||
console.log(apiKey);
|
||||
}, (error: any) => {
|
||||
return (error.argument === "projectId" && error.reason === "projectSecret requires a projectId");
|
||||
});
|
||||
|
||||
// Fails on invalid projectSecret type
|
||||
assert.throws(() => {
|
||||
const apiKey = ethers.providers.InfuraProvider.getApiKey({
|
||||
projectId: projectId,
|
||||
projectSecret: 1234
|
||||
});
|
||||
console.log(apiKey);
|
||||
}, (error: any) => {
|
||||
return (error.argument === "projectSecret" && error.reason === "invalid projectSecret");
|
||||
});
|
||||
|
||||
{
|
||||
const provider = new ethers.providers.InfuraProvider("homestead", {
|
||||
projectId: projectId,
|
||||
projectSecret: projectSecret
|
||||
});
|
||||
assert.equal(provider.network.name, "homestead");
|
||||
assert.equal(provider.apiKey, projectId);
|
||||
assert.equal(provider.projectId, projectId);
|
||||
assert.equal(provider.projectSecret, projectSecret);
|
||||
}
|
||||
|
||||
// Attempt an unsupported network
|
||||
assert.throws(() => {
|
||||
const provider = new ethers.providers.InfuraProvider("imaginary");
|
||||
console.log(provider);
|
||||
}, (error: any) => {
|
||||
return (error.argument === "network" && error.reason === "unsupported network");
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test WebSocketProvider", function() {
|
||||
async function testWebSocketProvider(provider: ethers.providers.WebSocketProvider): Promise<void> {
|
||||
await provider.destroy();
|
||||
}
|
||||
|
||||
it("InfuraProvider.getWebSocketProvider", async function() {
|
||||
const provider = ethers.providers.InfuraProvider.getWebSocketProvider();
|
||||
await testWebSocketProvider(provider);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test Events", function() {
|
||||
async function testBlockEvent(provider: ethers.providers.Provider) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let firstBlockNumber: number = null;
|
||||
const handler = (blockNumber: number) => {
|
||||
if (firstBlockNumber == null) {
|
||||
firstBlockNumber = blockNumber;
|
||||
return;
|
||||
}
|
||||
provider.removeListener("block", handler);
|
||||
if (firstBlockNumber + 1 === blockNumber) {
|
||||
resolve(true);
|
||||
} else {
|
||||
reject(new Error("blockNumber fail"));
|
||||
}
|
||||
};
|
||||
provider.on("block", handler);
|
||||
});
|
||||
}
|
||||
|
||||
it("InfuraProvider", async function() {
|
||||
this.timeout(50000);
|
||||
const provider = new ethers.providers.InfuraProvider("rinkeby");
|
||||
await testBlockEvent(provider);
|
||||
});
|
||||
});
|
||||
|
@ -198,6 +198,31 @@ describe('Test Unit Conversion', function () {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("formats with commify", function() {
|
||||
const tests: { [ testcase: string ]: string } = {
|
||||
"0.0": "0.0",
|
||||
".0": "0.0",
|
||||
"0.": "0.0",
|
||||
"00.00": "0.0",
|
||||
|
||||
"100.000": "100.0",
|
||||
"100.0000": "100.0",
|
||||
"1000.000": "1,000.0",
|
||||
"1000.0000": "1,000.0",
|
||||
|
||||
"100.123": "100.123",
|
||||
"100.1234": "100.1234",
|
||||
"1000.1234": "1,000.1234",
|
||||
"1000.12345": "1,000.12345",
|
||||
|
||||
"998998998998.123456789": "998,998,998,998.123456789",
|
||||
};
|
||||
|
||||
Object.keys(tests).forEach((test) => {
|
||||
assert.equal(ethers.utils.commify(test), tests[test]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -216,6 +241,13 @@ describe('Test Namehash', function() {
|
||||
'computes namehash(' + test.name + ')');
|
||||
});
|
||||
});
|
||||
|
||||
it("isValidName", function() {
|
||||
assert.ok(ethers.utils.isValidName("ricmoo.eth"));
|
||||
|
||||
assert.ok(!ethers.utils.isValidName(""));
|
||||
assert.ok(!ethers.utils.isValidName("ricmoo..eth"));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test ID Hash Functions', function () {
|
||||
@ -255,7 +287,7 @@ describe('Test Solidity Hash Functions', function() {
|
||||
const tests: Array<TestCase> = loadTests('solidity-hashes');
|
||||
|
||||
function test(funcName: string, testKey: 'keccak256' | 'sha256') {
|
||||
it(('computes ' + funcName + ' correctly'), function() {
|
||||
it(`computes ${ funcName } correctly`, function() {
|
||||
this.timeout(120000);
|
||||
|
||||
tests.forEach((test, index) => {
|
||||
@ -269,11 +301,33 @@ describe('Test Solidity Hash Functions', function() {
|
||||
|
||||
test('Keccak256', 'keccak256');
|
||||
test('Sha256', 'sha256');
|
||||
|
||||
const testsInvalid = [
|
||||
"uint0", // number - null length
|
||||
"uint1", // number - not byte-aligned
|
||||
"uint08", // number - leading zeros
|
||||
"uint266", // number - out-of-range
|
||||
"bytes0", // bytes - null length
|
||||
"bytes02", // bytes - leading zeros
|
||||
"bytes33", // bytes - out-of-range
|
||||
"purple" // invalid type
|
||||
];
|
||||
|
||||
testsInvalid.forEach((type) => {
|
||||
it(`disallows invalid type "${ type }"`, function() {
|
||||
assert.throws(() => {
|
||||
ethers.utils.solidityPack([ type ], [ "0x12" ]);
|
||||
}, (error: Error) => {
|
||||
const message = error.message;
|
||||
return (message.match(/invalid([a-z ]*) type/) && message.indexOf(type) >= 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test Hash Functions', function() {
|
||||
|
||||
const tests: Array<{ data: string, keccak256: string, sha256: string }> = loadTests('hashes');
|
||||
const tests: Array<TestCase.Hash> = loadTests('hashes');
|
||||
|
||||
it('computes keccak256 correctly', function() {
|
||||
this.timeout(120000);
|
||||
@ -282,12 +336,19 @@ describe('Test Hash Functions', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('computes sha2566 correctly', function() {
|
||||
it('computes sha2-256 correctly', function() {
|
||||
this.timeout(120000);
|
||||
tests.forEach(function(test) {
|
||||
assert.equal(ethers.utils.sha256(test.data), test.sha256, ('SHA256 - ' + test.data));
|
||||
});
|
||||
});
|
||||
|
||||
it('computes sha2-512 correctly', function() {
|
||||
this.timeout(120000);
|
||||
tests.forEach(function(test) {
|
||||
assert.equal(ethers.utils.sha512(test.data), test.sha512, ('SHA512 - ' + test.data));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test Solidity splitSignature', function() {
|
||||
@ -561,3 +622,46 @@ describe("BigNumber", function() {
|
||||
// @TODO: Add more tests here
|
||||
|
||||
});
|
||||
|
||||
describe("Logger", function() {
|
||||
const logger = new ethers.utils.Logger("testing/0.0");
|
||||
|
||||
it("checkArgumentCount", function() {
|
||||
logger.checkArgumentCount(3, 3);
|
||||
});
|
||||
|
||||
it("checkArgumentCount - too few", function() {
|
||||
assert.throws(() => {
|
||||
logger.checkArgumentCount(1, 3);
|
||||
}, (error: any) => {
|
||||
return error.code === ethers.utils.Logger.errors.MISSING_ARGUMENT;
|
||||
});
|
||||
});
|
||||
|
||||
it("checkArgumentCount - too many", function() {
|
||||
assert.throws(() => {
|
||||
logger.checkArgumentCount(3, 1);
|
||||
}, (error: any) => {
|
||||
return error.code === ethers.utils.Logger.errors.UNEXPECTED_ARGUMENT;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
describe("Base58 Coder", function() {
|
||||
it("decodes", function() {
|
||||
assert.equal(ethers.utils.Base58.decode("JxF12TrwUP45BMd"), "Hello World");
|
||||
});
|
||||
|
||||
it("encodes", function() {
|
||||
assert.equal(ethers.utils.Base58.encode("Hello World"), "JxF12TrwUP45BMd");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Web Fetch", function() {
|
||||
it("fetches JSON", async function() {
|
||||
const url = "https:/\/api.etherscan.io/api?module=stats&action=ethprice&apikey=9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB";
|
||||
const getData = ethers.utils.fetchJson(url)
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@ describe('Test JSON Wallets', function() {
|
||||
|
||||
let tests: Array<TestCase.Wallet> = loadTests('wallets');
|
||||
tests.forEach(function(test) {
|
||||
it(('decrypts wallet - ' + test.name), function() {
|
||||
it(('decrypts wallet - ' + test.name), async function() {
|
||||
this.timeout(1200000);
|
||||
|
||||
if (test.hasAddress) {
|
||||
@ -20,16 +20,49 @@ describe('Test JSON Wallets', function() {
|
||||
'detect encrypted JSON wallet');
|
||||
}
|
||||
|
||||
return ethers.Wallet.fromEncryptedJson(test.json, test.password).then((wallet) => {
|
||||
assert.equal(wallet.privateKey, test.privateKey,
|
||||
'generated correct private key - ' + wallet.privateKey);
|
||||
assert.equal(wallet.address.toLowerCase(), test.address,
|
||||
'generate correct address - ' + wallet.address);
|
||||
if (test.mnemonic) {
|
||||
assert.equal(wallet.mnemonic.phrase, test.mnemonic,
|
||||
'mnemonic enabled encrypted wallet has a mnemonic phrase');
|
||||
}
|
||||
});
|
||||
const wallet = await ethers.Wallet.fromEncryptedJson(test.json, test.password);
|
||||
|
||||
assert.equal(wallet.privateKey, test.privateKey,
|
||||
'generated correct private key - ' + wallet.privateKey);
|
||||
|
||||
assert.equal(wallet.address.toLowerCase(), test.address,
|
||||
'generate correct address - ' + wallet.address);
|
||||
|
||||
assert.equal(wallet.address.toLowerCase(), test.address,
|
||||
'generate correct address - ' + wallet.address);
|
||||
|
||||
const walletAddress = await wallet.getAddress();
|
||||
assert.equal(walletAddress.toLowerCase(), test.address,
|
||||
'generate correct address - ' + wallet.address);
|
||||
|
||||
// Test connect
|
||||
{
|
||||
const provider = new ethers.providers.EtherscanProvider();
|
||||
const walletConnected = wallet.connect(provider);
|
||||
assert.equal(walletConnected.provider, provider, "provider is connected");
|
||||
assert.ok((wallet.provider == null), "original wallet provider is null");
|
||||
assert.equal(walletConnected.address.toLowerCase(), test.address,
|
||||
"connected correct address - " + wallet.address);
|
||||
}
|
||||
|
||||
// Make sure it can accept a SigningKey
|
||||
{
|
||||
const wallet2 = new ethers.Wallet(wallet._signingKey());
|
||||
assert.equal(wallet2.privateKey, test.privateKey,
|
||||
'generated correct private key - ' + wallet2.privateKey);
|
||||
}
|
||||
|
||||
// Test the sync decryption (this wallet is light, so it is safe)
|
||||
if (test.name === "life") {
|
||||
const wallet2 = ethers.Wallet.fromEncryptedJsonSync(test.json, test.password);
|
||||
assert.equal(wallet2.privateKey, test.privateKey,
|
||||
'generated correct private key - ' + wallet2.privateKey);
|
||||
}
|
||||
|
||||
if (test.mnemonic) {
|
||||
assert.equal(wallet.mnemonic.phrase, test.mnemonic,
|
||||
'mnemonic enabled encrypted wallet has a mnemonic phrase');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -177,7 +210,26 @@ describe('Test Transaction Signing and Parsing', function() {
|
||||
assert.equal(ethers.utils.serializeTransaction(transaction, signature), test.signedTransactionChainId5,
|
||||
'signs transaction (eip155)');
|
||||
})();
|
||||
});
|
||||
});
|
||||
|
||||
tests.forEach((test) => {
|
||||
it(('wallet signs transaction - ' + test.name), async function() {
|
||||
this.timeout(120000);
|
||||
|
||||
const wallet = new ethers.Wallet(test.privateKey);
|
||||
const transaction = {
|
||||
to: test.to,
|
||||
data: test.data,
|
||||
gasLimit: test.gasLimit,
|
||||
gasPrice: test.gasPrice,
|
||||
value: test.value,
|
||||
nonce: ((<any>(test.nonce)) === "0x") ? 0: test.nonce,
|
||||
chainId: 5
|
||||
};
|
||||
|
||||
const signedTx = await wallet.signTransaction(transaction);
|
||||
assert.equal(signedTx, test.signedTransactionChainId5);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -237,8 +289,8 @@ describe('Test Signing Messages', function() {
|
||||
tests.forEach(function(test) {
|
||||
it(('verifies a message "' + test.name + '"'), function() {
|
||||
this.timeout(120000);
|
||||
// let address = ethers.utils.verifyMessage(test.message, test.signature);
|
||||
// assert.equal(address, test.address, 'verifies message signature');
|
||||
let address = ethers.utils.verifyMessage(test.message, test.signature);
|
||||
assert.equal(address, test.address, 'verifies message signature');
|
||||
});
|
||||
});
|
||||
|
||||
@ -261,3 +313,50 @@ describe("Serialize Transactions", function() {
|
||||
//console.log(result);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Wallet Errors", function() {
|
||||
it("fails on privateKey/address mismatch", function() {
|
||||
assert.throws(() => {
|
||||
const wallet = new ethers.Wallet({
|
||||
privateKey: "0x6a73cd9b03647e83ef937888a5258a26e4c766dbf41ddd974f15e32d09cfe9c0",
|
||||
address: "0x3f4f037dfc910a3517b9a5b23cf036ffae01a5a7"
|
||||
});
|
||||
console.log(wallet);
|
||||
}, (error: any) => {
|
||||
return error.reason === "privateKey/address mismatch";
|
||||
});
|
||||
});
|
||||
|
||||
it("fails on mnemonic/address mismatch", function() {
|
||||
assert.throws(() => {
|
||||
const wallet = new ethers.Wallet(<any>{
|
||||
privateKey: "0x6a73cd9b03647e83ef937888a5258a26e4c766dbf41ddd974f15e32d09cfe9c0",
|
||||
address: "0x4Dfe3BF68c80f19083FF90E6a852fC876AE7429b",
|
||||
mnemonic: {
|
||||
phrase: "pact grief smile usage kind pledge river excess garbage mixed olive receive"
|
||||
}
|
||||
});
|
||||
console.log(wallet);
|
||||
}, (error: any) => {
|
||||
return error.reason === "mnemonic/address mismatch";
|
||||
});
|
||||
});
|
||||
|
||||
it("fails on from mismatch", function() {
|
||||
const wallet = new ethers.Wallet("0x6a73cd9b03647e83ef937888a5258a26e4c766dbf41ddd974f15e32d09cfe9c0");
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
await wallet.signTransaction({
|
||||
from: "0x3f4f037dfc910a3517b9a5b23cf036ffae01a5a7"
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.code === ethers.utils.Logger.errors.INVALID_ARGUMENT && error.argument === "transaction.from") {
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reject(new Error("assert failed; did not throw"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ import { loadTests, TestCase } from "@ethersproject/testcases";
|
||||
|
||||
function checkWordlist(content: string, wordlist: ethers.Wordlist): void {
|
||||
let words = content.split('\n');
|
||||
|
||||
it('matches wordlists for ' + wordlist.locale, function() {
|
||||
for (let i = 0; i < 2048; i++) {
|
||||
let actual = wordlist.getWord(i);
|
||||
@ -15,6 +16,21 @@ function checkWordlist(content: string, wordlist: ethers.Wordlist): void {
|
||||
assert.equal(actual, expected, 'failed to match word ' + i + ': ' + words[i] + ' !=' + wordlist.getWord(i));
|
||||
}
|
||||
});
|
||||
|
||||
it ("splitting and joining are equivalent", function() {
|
||||
const words: Array<string> = [ ];
|
||||
for (let i = 0; i < 12; i++) {
|
||||
words.push(wordlist.getWord(i));
|
||||
}
|
||||
|
||||
const phrase = wordlist.join(words);
|
||||
|
||||
const words2 = wordlist.split(phrase);
|
||||
const phrase2 = wordlist.join(words2);
|
||||
|
||||
assert.deepStrictEqual(words2, words, "split words");
|
||||
assert.deepStrictEqual(phrase2, phrase, "re-joined words");
|
||||
});
|
||||
}
|
||||
|
||||
describe('Check Wordlists', function() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user