2
0
mirror of synced 2025-02-23 11:38:42 +00:00

Added tests to help fill out coverage tests.

This commit is contained in:
Richard Moore 2020-07-13 07:30:49 -04:00
parent 79b1da130b
commit 1cfe4962aa
No known key found for this signature in database
GPG Key ID: 665176BE8E9DC651
5 changed files with 436 additions and 16 deletions

View File

@ -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;
});
});
});

View File

@ -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);
});
});

View File

@ -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)
});
});
*/

View File

@ -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"));
});
});
});

View File

@ -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() {