Migrated most test cases to mocha and added pre-generated gzipped test suite.
This commit is contained in:
parent
4a3d68eada
commit
44729ffba9
99
tests/README.md
Normal file
99
tests/README.md
Normal file
@ -0,0 +1,99 @@
|
||||
Ethers Test Suite
|
||||
=================
|
||||
|
||||
There are a lot of test cases, and it can take a while for them to all run.
|
||||
|
||||
Please be patient.
|
||||
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
**Node.js:**
|
||||
|
||||
```
|
||||
# Test everything
|
||||
> npm test
|
||||
|
||||
|
||||
# Test just one specific package
|
||||
|
||||
# Test the Solidity ABI coder
|
||||
# - See tests/contract-interface.json.gz
|
||||
> ./node_modules/.bin/mocha test-contract-interface.js
|
||||
|
||||
# Test HD Wallet derivations
|
||||
# - See tests/hdnode.json.gz
|
||||
> ./node_modules/.bin/mocha test-hdnode.js
|
||||
|
||||
# Test general utilities
|
||||
# - See tests/namehash.json.gz
|
||||
# - See tests/rlp-coder.json.gz
|
||||
# - See tests/units.json.gz
|
||||
> ./node_modules/.bin/mocha test-utils.js
|
||||
|
||||
# Test accounts and addresses
|
||||
# - See tests/accounts.json.gz
|
||||
> ./node_modules/.bin/mocha test-account.js
|
||||
|
||||
# Test encrypting/decrypting JSON wallets and transaction parsing/signing
|
||||
# - See tests/transactions.json.gz
|
||||
# - See tests/wallets.json.gz
|
||||
> ./node_modules/.bin/mocha test-wallet.js
|
||||
|
||||
|
||||
# This test case has not yet been migrated to mocha
|
||||
> nodeunit run-provider.js
|
||||
```
|
||||
|
||||
|
||||
Test Cases
|
||||
----------
|
||||
|
||||
The testcases take up a large amount of space, so they are gzipped in the
|
||||
`tests/` folder. See `./utils.js` for saving and loading.
|
||||
|
||||
To dump a test case from the terminal, you can use:
|
||||
|
||||
```
|
||||
/Users/ethers> cat ./tests/accounts.json.gz | gunzip
|
||||
```
|
||||
|
||||
|
||||
Building Testcases
|
||||
------------------
|
||||
|
||||
Each suite of testcases is produced from a variety of sources. Many include a
|
||||
specific set of test vecotrs as well as procedurally generated tests using known
|
||||
correct implementations.
|
||||
|
||||
The `contract-interface` test cases are created by selecting a (deterministically) random
|
||||
set of types and values, a solidity contract is then created to represent a contract with
|
||||
the correct return types and values, which is then compiled and deployed to a local
|
||||
Ethereum node, then executed once mined.
|
||||
|
||||
As a result, genearting the test cases can take quite some time. So, they are generated using
|
||||
a separate set of files found in make-tests.
|
||||
|
||||
- make-accounts
|
||||
- make-contract-interface
|
||||
- make-hdnode
|
||||
- makr-rlpcoder
|
||||
- make-transaction
|
||||
- make-wallets
|
||||
|
||||
Additional Test Vectors:
|
||||
- **make-tests/test-mnemonics** -- The trezor test vectors for BIP39
|
||||
- **make-tests/test-wallets** -- Sample JSON Wallets (crowdsale and Geth)
|
||||
|
||||
All generated JSON test files are then placed gzipped in `tests` with the extension '.json.gz'.
|
||||
|
||||
|
||||
Adding Test Cases
|
||||
-----------------
|
||||
|
||||
For any patch, feature upgrade or pull request of any sort, there must be relevant
|
||||
test cases added and all test cases must pass.
|
||||
|
||||
If you report a bug and provide test cases, it will get attention sooner.
|
||||
|
@ -5,54 +5,99 @@ var fs = require('fs');
|
||||
var ethereumUtil = require('ethereumjs-util');
|
||||
var iban = require('web3/lib/web3/iban.js');
|
||||
|
||||
var utils = require('./utils.js');
|
||||
var utils = require('../utils.js');
|
||||
|
||||
function icap(address) {
|
||||
address = (iban.fromAddress(address))._iban;
|
||||
return address;
|
||||
}
|
||||
|
||||
var Tests = [
|
||||
// Edge-cases
|
||||
'0x0000000000000000000000000000000000000000',
|
||||
'0x0000000000000000000000000000000000000001',
|
||||
'0xfffffffffffffffffffffffffffffffffffffffe',
|
||||
'0xffffffffffffffffffffffffffffffffffffffff',
|
||||
var Output = [];
|
||||
|
||||
// Exposes a padding bug in Web3
|
||||
// See: https://github.com/ethereum/web3.js/pull/417
|
||||
'0x03582910e5bc7a12793da58559aba9a6c4138e44',
|
||||
]
|
||||
// Some specific addresses to check
|
||||
(function() {
|
||||
var Tests = [
|
||||
// Edge-cases
|
||||
'0x0000000000000000000000000000000000000000',
|
||||
'0x0000000000000000000000000000000000000001',
|
||||
'0x0000000000000000000000000000000000000010',
|
||||
'0xfffffffffffffffffffffffffffffffffffffffe',
|
||||
'0xffffffffffffffffffffffffffffffffffffffff',
|
||||
|
||||
var OutputAddresses = [];
|
||||
var OutputPrivateKeys = [];
|
||||
// Exposes a padding bug in Web3
|
||||
// See: https://gist.github.com/ricmoo/dbc2133ae2a20978eaf7
|
||||
// See: https://github.com/ethereum/web3.js/pull/417
|
||||
'0x03582910e5bc7a12793da58559aba9a6c4138e44',
|
||||
'0x00582910e5bc7a12793da58559aba9a6c4138e44',
|
||||
]
|
||||
|
||||
Tests.forEach(function(address) {
|
||||
OutputAddresses.push({
|
||||
address: address,
|
||||
checksumAddress: ethereumUtil.toChecksumAddress(address),
|
||||
icapAddress: icap(address)
|
||||
});
|
||||
Tests.forEach(function(address) {
|
||||
Output.push({
|
||||
address: address,
|
||||
checksumAddress: ethereumUtil.toChecksumAddress(address),
|
||||
icapAddress: icap(address),
|
||||
index: Output.length,
|
||||
name: ('address-' + address)
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
// Some specific private keys to check
|
||||
(function() {
|
||||
var Tests = [
|
||||
// Edge-cases
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000001',
|
||||
'0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00',
|
||||
'0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0',
|
||||
'0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
'0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
'0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f',
|
||||
'0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
|
||||
]
|
||||
|
||||
Tests.forEach(function(privateKey) {
|
||||
var privateKeyBuffer = new Buffer(privateKey.substring(2), 'hex');
|
||||
var address = '0x' + ethereumUtil.privateToAddress(privateKeyBuffer).toString('hex');
|
||||
Output.push({
|
||||
address: address,
|
||||
checksumAddress: ethereumUtil.toChecksumAddress(address),
|
||||
icapAddress: icap(address),
|
||||
index: Output.length,
|
||||
name: ('privateKey-' + privateKey),
|
||||
privateKey: privateKey
|
||||
});
|
||||
});
|
||||
})();
|
||||
/*
|
||||
Output.push({
|
||||
error: 'invalid private key',
|
||||
index: Ouput.length,
|
||||
name: 'privateKey-tooBig',
|
||||
privateKey: '0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
|
||||
});
|
||||
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
var privateKey = utils.randomBytes('accounts-' + i, 32);
|
||||
Output.push({
|
||||
error: 'invalid private key',
|
||||
index: Ouput.length,
|
||||
name: 'privateKey-zero',
|
||||
privateKey: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
});
|
||||
*/
|
||||
|
||||
// Add 1024 random private keys (checks for nibble and byte padding bugs)
|
||||
for (var i = 0; i < 1024; i++) {
|
||||
var privateKey = new Buffer(utils.randomBytes('accounts-' + i, 32));
|
||||
var address = '0x' + ethereumUtil.privateToAddress(new Buffer(privateKey)).toString('hex');
|
||||
|
||||
OutputAddresses.push({
|
||||
Output.push({
|
||||
address: address,
|
||||
checksumAddress: ethereumUtil.toChecksumAddress(address),
|
||||
icapAddress: icap(address),
|
||||
});
|
||||
|
||||
OutputPrivateKeys.push({
|
||||
address: address,
|
||||
checksumAddress: ethereumUtil.toChecksumAddress(address),
|
||||
icapAddress: icap(address),
|
||||
privateKey: utils.hexlify(privateKey),
|
||||
index: Output.length,
|
||||
name: ('random-' + i),
|
||||
privateKey: '0x' + privateKey.toString('hex'),
|
||||
});
|
||||
}
|
||||
|
||||
utils.saveTestcase('addresses', OutputAddresses);
|
||||
utils.saveTestcase('private-keys', OutputPrivateKeys);
|
||||
utils.saveTests('accounts', Output);
|
||||
|
||||
|
@ -4,7 +4,7 @@ var bip39 = require('bip39');
|
||||
var HDNode = require('bitcoinjs-lib').HDNode;
|
||||
var ethereumUtil = require('ethereumjs-util');
|
||||
|
||||
var utils = require('./utils.js');
|
||||
var utils = require('../utils.js');
|
||||
|
||||
function getPath(seed) {
|
||||
var path = 'm';
|
||||
@ -61,7 +61,7 @@ trezor.english.forEach(function(testcase, i) {
|
||||
};
|
||||
});
|
||||
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
for (var i = 0; i < 1024; i++) {
|
||||
var strength = 16 + 4 * utils.randomNumber('random-1-' + i, 0, 5);
|
||||
var entropy = utils.randomHexString('random-2-' + i, strength);
|
||||
|
||||
@ -108,4 +108,4 @@ TestcaseNames.forEach(function(testcase) {
|
||||
Output.push(Testcases[testcase]);
|
||||
});
|
||||
|
||||
utils.saveTestcase('hdnode', Output);
|
||||
utils.saveTests('hdnode', Output);
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import sha3
|
||||
|
||||
|
||||
def keccak256(data):
|
||||
hasher = sha3.keccak_256()
|
||||
hasher.update(data)
|
||||
@ -43,3 +45,4 @@ for i in xrange(0, len(Tests)):
|
||||
|
||||
with file('../tests/namehash.json', 'w') as f:
|
||||
f.write(json.dumps(Tests))
|
||||
os.system('cat ../test/namehash.json | gzip > ../tests/namehash.json.gz');
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
var rlp = require('rlp');
|
||||
|
||||
var utils = require('./utils.js');
|
||||
var utils = require('../utils.js');
|
||||
|
||||
var nullBuffer = new Buffer('');
|
||||
var shortBuffer = new Buffer('Hello World');
|
||||
@ -75,4 +75,4 @@ testNames.forEach(function(testName) {
|
||||
});
|
||||
console.log(Output);
|
||||
|
||||
utils.saveTestcase('rlp-coder', Output);
|
||||
utils.saveTests('rlp-coder', Output);
|
||||
|
@ -3,7 +3,7 @@
|
||||
var ethereumUtil = require('ethereumjs-util');
|
||||
var ethereumTx = require('ethereumjs-tx');
|
||||
|
||||
var utils = require('./utils.js');
|
||||
var utils = require('../utils.js');
|
||||
|
||||
|
||||
var Output = [];
|
||||
@ -130,4 +130,4 @@ Output.sort(function(a, b) {
|
||||
return 0;
|
||||
});
|
||||
|
||||
utils.saveTestcase('transactions', Output);
|
||||
utils.saveTests('transactions', Output);
|
||||
|
@ -3,7 +3,7 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var utils = require('./utils.js');
|
||||
var utils = require('../utils.js');
|
||||
|
||||
function prefixAddress(address) {
|
||||
if (address.substring(0, 2) !== '0x') {
|
||||
@ -38,6 +38,8 @@ var walletPath = path.join(__dirname, 'test-wallets');
|
||||
fs.readdirSync(walletPath).forEach(function(filename) {
|
||||
var data = require(path.join(walletPath, filename));
|
||||
|
||||
var name = filename.substring(0, filename.length - 5).split('-')[1];
|
||||
|
||||
// The password is the last segment of the filename
|
||||
var password = filename.substring(0, filename.length - 5).split('-');
|
||||
password = password[password.length - 1];
|
||||
@ -49,6 +51,7 @@ fs.readdirSync(walletPath).forEach(function(filename) {
|
||||
type: 'crowdsale',
|
||||
address: prefixAddress(data.ethaddr),
|
||||
json: JSON.stringify(data),
|
||||
name: name,
|
||||
password: password,
|
||||
privateKey: privateKeys[prefixAddress(data.ethaddr)],
|
||||
});
|
||||
@ -58,10 +61,11 @@ fs.readdirSync(walletPath).forEach(function(filename) {
|
||||
type: 'secret-storage',
|
||||
address: prefixAddress(data.address),
|
||||
json: JSON.stringify(data),
|
||||
name: name,
|
||||
password: password,
|
||||
privateKey: privateKeys[prefixAddress(data.address)],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
utils.saveTestcase('wallets', Output);
|
||||
utils.saveTests('wallets', Output);
|
||||
|
@ -1,52 +0,0 @@
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var utils = require('../../utils');
|
||||
|
||||
function randomBytes(seed, lower, upper) {
|
||||
if (!upper) { upper = lower; }
|
||||
|
||||
if (upper === 0 && upper === lower) { return new Uint8Array(0); }
|
||||
|
||||
seed = utils.toUtf8Bytes(seed);
|
||||
|
||||
var result = utils.arrayify(utils.keccak256(seed));
|
||||
while (result.length < upper) {
|
||||
result = utils.concat([result, utils.keccak256(utils.concat([seed, result]))]);
|
||||
}
|
||||
|
||||
var top = utils.arrayify(utils.keccak256(result));
|
||||
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
|
||||
|
||||
return result.slice(0, lower + parseInt((upper - lower) * percent));
|
||||
}
|
||||
|
||||
function randomHexString(seed, lower, upper) {
|
||||
return utils.hexlify(randomBytes(seed, lower, upper));
|
||||
}
|
||||
|
||||
function randomNumber(seed, lower, upper) {
|
||||
var top = randomBytes(seed, 3);
|
||||
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
|
||||
return lower + parseInt((upper - lower) * percent);
|
||||
}
|
||||
|
||||
function saveTestcase(testcaseName, json) {
|
||||
var data = JSON.stringify(json, undefined, ' ');
|
||||
var filename = path.join(__dirname, '../tests/', testcaseName + '.json');
|
||||
fs.writeFileSync(filename, data);
|
||||
|
||||
console.log('Save testcase: ' + filename);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
randomBytes: randomBytes,
|
||||
randomHexString: randomHexString,
|
||||
randomNumber: randomNumber,
|
||||
|
||||
arrayify: utils.arrayify,
|
||||
hexlify: utils.hexlify,
|
||||
|
||||
saveTestcase: saveTestcase,
|
||||
};
|
@ -16,12 +16,13 @@
|
||||
"grunt-browserify": "^5.0.0",
|
||||
"grunt-contrib-uglify": "^1.0.1",
|
||||
"promise-rationing": "0.0.1",
|
||||
"mocha": "^3.2.0",
|
||||
"rlp": "2.0.0",
|
||||
"solc": "0.3.5",
|
||||
"web3": "0.18.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node index.js"
|
||||
"test": "./node_modules/.bin/mocha --timeout 100000 test-*.js"
|
||||
},
|
||||
"keywords": [
|
||||
"Ethereum",
|
||||
|
41
tests/test-account.js
Normal file
41
tests/test-account.js
Normal file
@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
var utils = require('./utils');
|
||||
|
||||
describe('Private key generation', function() {
|
||||
var Wallet = require('../wallet/Wallet');
|
||||
|
||||
var tests = utils.loadTests('accounts');
|
||||
tests.forEach(function(test) {
|
||||
if (!test.privateKey) { return; }
|
||||
it(('correctly converts private key - ' + test.name), function() {
|
||||
var wallet = new Wallet(test.privateKey);
|
||||
assert.equal(wallet.address.toLowerCase(), test.address.toLowerCase(),
|
||||
'correctly computes privateKey - ' + test.privateKey);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checksum and ICAP address generation', function() {
|
||||
var getAddress = require('../utils/address').getAddress;
|
||||
|
||||
var tests = utils.loadTests('accounts');
|
||||
tests.forEach(function(test) {
|
||||
it(('correctly transforms address - ' + test.name), function() {
|
||||
assert.equal(getAddress(test.address), test.checksumAddress,
|
||||
'correctly computes checksum address from address');
|
||||
assert.equal(getAddress(test.address, true), test.icapAddress,
|
||||
'correctly computes ICAP address from address');
|
||||
assert.equal(getAddress(test.checksumAddress), test.checksumAddress,
|
||||
'correctly computes checksum address from checksum address');
|
||||
assert.equal(getAddress(test.checksumAddress, true), test.icapAddress,
|
||||
'correctly computes ICAP address from checksum address');
|
||||
assert.equal(getAddress(test.icapAddress), test.checksumAddress,
|
||||
'correctly computes checksum address from icap address');
|
||||
assert.equal(getAddress(test.icapAddress, true), test.icapAddress,
|
||||
'correctly computes ICAP address from icap address');
|
||||
});
|
||||
});
|
||||
});
|
164
tests/test-contract-interface.js
Normal file
164
tests/test-contract-interface.js
Normal file
@ -0,0 +1,164 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
var utils = require('./utils');
|
||||
|
||||
// Set this to true to compare results against Web3 coder
|
||||
var testWeb3 = false;
|
||||
|
||||
|
||||
var FORMAT_WEB3 = 'web3';
|
||||
|
||||
var web3Coder = null;
|
||||
if (testWeb3) {
|
||||
web3Coder = require('web3/lib/solidity/coder');
|
||||
}
|
||||
|
||||
|
||||
function equals(a, b) {
|
||||
// Array (treat recursively)
|
||||
if (Array.isArray(a)) {
|
||||
if (!Array.isArray(b) || a.length !== b.length) { return false; }
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (!equals(a[i], b[i])) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (testWeb3) {
|
||||
if (a.toJSON && a.minus) { a = utils.bigNumberify(a.toString(10)); }
|
||||
if (b.toJSON && b.minus) { b = utils.bigNumberify(b.toString(10)); }
|
||||
}
|
||||
|
||||
// BigNumber
|
||||
if (a.eq) {
|
||||
if (!a.eq(b)) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
// Uint8Array
|
||||
if (a.buffer) {
|
||||
if (!utils.isHexString(b)) { return false; }
|
||||
b = utils.arrayify(b);
|
||||
|
||||
if (!b.buffer || a.length !== b.length) { return false; }
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) { return false; }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (testWeb3) {
|
||||
if (a.match && a.match(/^0x[0-9A-Fa-f]{40}$/)) { a = a.toLowerCase(); }
|
||||
if (b.match && b.match(/^0x[0-9A-Fa-f]{40}$/)) { b = b.toLowerCase(); }
|
||||
}
|
||||
|
||||
// Something else
|
||||
return a === b;
|
||||
}
|
||||
|
||||
|
||||
function getValues(object, format) {
|
||||
if (Array.isArray(object)) {
|
||||
var result = [];
|
||||
object.forEach(function(object) {
|
||||
result.push(getValues(object, format));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (object.type) {
|
||||
case 'number':
|
||||
if (format === FORMAT_WEB3) {
|
||||
var value = utils.bigNumberify(object.value);
|
||||
value.round = function() {
|
||||
return this;
|
||||
}
|
||||
value.lessThan = function(other) {
|
||||
return this.lt(other);
|
||||
}
|
||||
var toString = value.toString.bind(value);
|
||||
var toHexString = value.toHexString.bind(value);
|
||||
Object.defineProperty(value, 'toString', {
|
||||
value: function(format) {
|
||||
if (format === 16) { return toHexString().substring(2); }
|
||||
return toString();
|
||||
}
|
||||
});
|
||||
return value;
|
||||
}
|
||||
return utils.bigNumberify(object.value);
|
||||
|
||||
case 'boolean':
|
||||
case 'string':
|
||||
return object.value;
|
||||
|
||||
case 'buffer':
|
||||
if (format === FORMAT_WEB3) {
|
||||
return object.value.toLowerCase();
|
||||
}
|
||||
return utils.arrayify(object.value);
|
||||
|
||||
default:
|
||||
throw new Error('invalid type - ' + object.type);
|
||||
}
|
||||
}
|
||||
|
||||
describe('Contract Interface ABI Encoding', function() {
|
||||
var Interface = require('../contracts/index.js').Interface;
|
||||
|
||||
var tests = utils.loadTests('contract-interface');
|
||||
tests.forEach(function(test) {
|
||||
var values = getValues(JSON.parse(test.normalizedValues));
|
||||
var types = JSON.parse(test.types);
|
||||
var result = test.result;
|
||||
|
||||
var title = test.name + ' => (' + test.types + ') = (' + test.normalizedValues + ')';
|
||||
|
||||
it(('encodes paramters - ' + test.name + ' - ' + test.types), function() {
|
||||
var encoded = Interface.encodeParams(types, values);
|
||||
assert.equal(encoded, result, 'encoded data - ' + title);
|
||||
|
||||
if (testWeb3) {
|
||||
var valuesWeb3 = getValues(JSON.parse(test.normalizedValues), FORMAT_WEB3);
|
||||
var web3Encoded = '0x' + web3Coder.encodeParams(types, valuesWeb3);
|
||||
assert.equal(web3Encoded, result, 'web3 encoded data - ' + title);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Contract Interface ABI Decoding', function() {
|
||||
var Interface = require('../contracts/index.js').Interface;
|
||||
|
||||
var tests = utils.loadTests('contract-interface');
|
||||
tests.forEach(function(test) {
|
||||
var values = getValues(JSON.parse(test.normalizedValues));
|
||||
var valuesWeb3 = getValues(JSON.parse(test.normalizedValues), FORMAT_WEB3);
|
||||
var types = JSON.parse(test.types);
|
||||
var result = test.result;
|
||||
|
||||
var title = test.name + ' => (' + test.types + ') = (' + test.normalizedValues + ')';
|
||||
|
||||
it(('decodes parameters - ' + test.name + ' - ' + test.types), function() {
|
||||
var decoded = Interface.decodeParams(types, result);
|
||||
var decodedArray = Array.prototype.slice.call(decoded);;
|
||||
|
||||
assert.ok(equals(values, decodedArray), 'decoded parameters - ' + title);
|
||||
|
||||
if (testWeb3) {
|
||||
var badWeb3 = [ 'random-1116' ];
|
||||
if (badWeb3.indexOf(test.name) >= 0) {
|
||||
asset.ok(false, 'This testcase hangs in Web3');
|
||||
} else {
|
||||
var web3Decoded = web3Coder.decodeParams(types, result.substring(2));
|
||||
//console.dir(valuesWeb3, { depth: null });
|
||||
//console.dir(web3Decoded, { depth: null });
|
||||
assert.ok(equals(valuesWeb3, web3Decoded), 'web3 decoded data - ' + title);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
43
tests/test-hdnode.js
Normal file
43
tests/test-hdnode.js
Normal file
@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
var utils = require('./utils');
|
||||
|
||||
describe('Test HD Node Derivation', function(test) {
|
||||
var HDNode = require('../wallet/hdnode');
|
||||
var Wallet = require('../wallet/wallet');
|
||||
|
||||
var tests = utils.loadTests('hdnode');
|
||||
tests.forEach(function(test) {
|
||||
it('Derives the HD nodes - ' + test.name, function() {
|
||||
var rootNode = new HDNode.fromSeed(test.seed);
|
||||
test.hdnodes.forEach(function(nodeTest) {
|
||||
|
||||
var node = rootNode.derivePath(nodeTest.path);
|
||||
assert.equal(node.privateKey, nodeTest.privateKey,
|
||||
'Generates privateKey - ' + nodeTest.privateKey);
|
||||
|
||||
var wallet = new Wallet(node.privateKey);
|
||||
assert.equal(wallet.address.toLowerCase(), nodeTest.address,
|
||||
'Generates address - ' + nodeTest.privateKey);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test HD Mnemonic Phrases', function testMnemonic() {
|
||||
var HDNode = require('../wallet/hdnode');
|
||||
|
||||
var tests = utils.loadTests('hdnode');
|
||||
tests.forEach(function(test) {
|
||||
it(('converts mnemonic phrases - ' + test.name), function() {
|
||||
assert.equal(HDNode.entropyToMnemonic(test.entropy), test.mnemonic,
|
||||
'Converts entropy to mnemonic ' + test.name);
|
||||
assert.equal(HDNode.mnemonicToEntropy(test.mnemonic), test.entropy,
|
||||
'Converts mnemonic to entropy - ' + test.mnemonic);
|
||||
assert.equal(HDNode.mnemonicToSeed(test.mnemonic, test.password), test.seed,
|
||||
'Converts mnemonic to seed - ' + test.mnemonic + ':' + test.password);
|
||||
});
|
||||
});
|
||||
});
|
129
tests/test-utils.js
Normal file
129
tests/test-utils.js
Normal file
@ -0,0 +1,129 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
var utils = require('./utils');
|
||||
|
||||
function equals(a, b) {
|
||||
if (Array.isArray(a)) {
|
||||
if (!Array.isArray(b) || a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (!equals(a[i], b[i])) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return a === b;
|
||||
}
|
||||
|
||||
describe('Test Contract Address Generation', function() {
|
||||
|
||||
// @TODO: Mine a large collection of these from the blockchain
|
||||
|
||||
var getContractAddress = require('../utils/contract-address.js').getContractAddress;
|
||||
|
||||
// Transaction: 0x939aa17985bc2a52a0c1cba9497ef09e092355a805a8150e30e24b753bac6864
|
||||
var Tests = [
|
||||
{
|
||||
address: '0x3474627D4F63A678266BC17171D87f8570936622',
|
||||
name: 'tx-0x939aa17985bc2a52a0c1cba9497ef09e092355a805a8150e30e24b753bac6864',
|
||||
tx: {
|
||||
from: '0xb2682160c482eb985ec9f3e364eec0a904c44c23',
|
||||
nonce: 10,
|
||||
}
|
||||
},
|
||||
|
||||
// Ropsten: 0x5bdfd14fcc917abc2f02a30721d152a6f147f09e8cbaad4e0d5405d646c5c3e1
|
||||
{
|
||||
address: '0x0CcCC7507aEDf9FEaF8C8D731421746e16b4d39D',
|
||||
name: 'zero-nonce',
|
||||
tx: {
|
||||
from: '0xc6af6e1a78a6752c7f8cd63877eb789a2adb776c',
|
||||
nonce: 0
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
Tests.forEach(function(test) {
|
||||
it(('Computes the transaction address - ' + test.name), function() {
|
||||
assert.equal(getContractAddress(test.tx), test.address, 'computes the transaction address');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test RLP Coder', function () {
|
||||
var rlp = require('../utils/rlp.js');
|
||||
|
||||
var tests = utils.loadTests('rlp-coder');
|
||||
|
||||
tests.forEach(function(test) {
|
||||
it(('RLP coder encoded - ' + test.name), function() {
|
||||
assert.equal(rlp.encode(test.decoded), test.encoded, 'RLP encoded - ' + test.name);
|
||||
});
|
||||
});
|
||||
|
||||
tests.forEach(function(test) {
|
||||
it(('RLP coder decoded - ' + test.name), function() {
|
||||
assert.ok(equals(rlp.decode(test.encoded), test.decoded),
|
||||
'RLP decoded - ' + test.name);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test Unit Conversion', function () {
|
||||
var units = require('../utils/units.js');
|
||||
var bigNumberify = require('../utils/bignumber.js').bigNumberify;
|
||||
|
||||
var tests = utils.loadTests('units');
|
||||
tests.forEach(function(test) {
|
||||
var wei = bigNumberify(test.wei);
|
||||
var formatting = test.format || {};
|
||||
|
||||
it (('parses ' + test.ether + ' ether'), function() {
|
||||
assert.ok(units.parseEther(test.ether).eq(wei),
|
||||
'parsing ether failed - ' + test.name);
|
||||
});
|
||||
|
||||
it (('formats ' + wei.toHexString() + ' wei (options: ' + JSON.stringify(formatting) + ')'), function() {
|
||||
assert.equal(units.formatEther(wei, formatting), test.etherFormat,
|
||||
'formatting wei failed - ' + test.name);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Test Namehash', function() {
|
||||
var namehash = require('../utils/namehash');
|
||||
|
||||
var tests = utils.loadTests('namehash');
|
||||
tests.forEach(function(test) {
|
||||
it(('computes namehash - "' + test.name + '"'), function() {
|
||||
assert.equal(namehash(test.name), test.expected,
|
||||
'computes namehash(' + test.name + ')');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test ID hash function', function () {
|
||||
var id = require('../utils/id');
|
||||
|
||||
var tests = [
|
||||
{
|
||||
name: 'setAddr signature hash',
|
||||
text: 'setAddr(bytes32,address)',
|
||||
expected: '0xd5fa2b00b0756613052388dd576d941ba16904757996b8bb03a737ef4fd1f9ce'
|
||||
}
|
||||
]
|
||||
|
||||
tests.forEach(function(test) {
|
||||
it(('computes id - ' + test.name), function() {
|
||||
var value = id(test.text);
|
||||
assert.equal(value, test.expected,
|
||||
'computes id(' + test.text + ')');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// @TODO: Cryptographics hashes?
|
147
tests/test-wallet.js
Normal file
147
tests/test-wallet.js
Normal file
@ -0,0 +1,147 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('./utils');
|
||||
|
||||
|
||||
describe('Test Brain Wallets', function() {
|
||||
var Wallet = require('../wallet/wallet');
|
||||
|
||||
var tests = [
|
||||
{
|
||||
address: '0xbed9d2E41BdD066f702C4bDB86eB3A3740101acC',
|
||||
name: 'simple brain wallet',
|
||||
password: 'password',
|
||||
username: 'ricmoo'
|
||||
}
|
||||
];
|
||||
|
||||
tests.forEach(function(test) {
|
||||
it(('computes the brain wallet for ' + test.name), function() {
|
||||
return Wallet.fromBrainWallet(test.username, test.password).then(function(wallet) {
|
||||
assert.equal(wallet.address, test.address,
|
||||
'computed brain wallet for ' + test.username + ':' + test.password);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test JSON Wallets', function() {
|
||||
var Wallet = require('../wallet/wallet');
|
||||
var tests = utils.loadTests('wallets');
|
||||
tests.forEach(function(test) {
|
||||
it(('decrypts wallet - ' + test.name), function() {
|
||||
assert.ok(Wallet.isEncryptedWallet(test.json),
|
||||
'detect encrypted JSON wallet');
|
||||
|
||||
return Wallet.fromEncryptedWallet(test.json, test.password).then(function(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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// A few extra test cases to test encrypting/decrypting
|
||||
['one', 'two', 'three'].forEach(function(i) {
|
||||
var password = 'foobar' + i;
|
||||
var wallet = new Wallet(utils.randomHexString('test-' + i, 32));
|
||||
it('encrypts and decrypts a random wallet - ' + i, function() {
|
||||
return wallet.encrypt(password).then(function(json) {
|
||||
return Wallet.fromEncryptedWallet(json, password).then(function(decryptedWallet) {
|
||||
assert.equal(decryptedWallet.address, wallet.address,
|
||||
'decrypted wallet - ' + wallet.privateKey);
|
||||
return decryptedWallet.encrypt(password).then(function(encryptedWallet) {
|
||||
var parsedWallet = JSON.parse(encryptedWallet);
|
||||
assert.equal(decryptedWallet.address.toLowerCase().substring(2), parsedWallet.address,
|
||||
're-encrypted wallet - ' + wallet.privateKey);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test Transaction Signing and Parsing', function() {
|
||||
var Wallet = require('../wallet/wallet');
|
||||
|
||||
var bigNumber = require('../utils/bignumber.js');
|
||||
var convert = require('../utils/convert.js');
|
||||
var getAddress = require('../utils/address.js').getAddress;
|
||||
|
||||
var tests = utils.loadTests('transactions');
|
||||
tests.forEach(function(test) {
|
||||
it(('parses and signs transaction - ' + test.name), function() {
|
||||
var wallet = new Wallet(test.privateKey);
|
||||
|
||||
var transaction = {};
|
||||
|
||||
var parsedTransaction = Wallet.parseTransaction(test.signedTransaction);
|
||||
|
||||
['nonce', 'gasLimit', 'gasPrice', 'to', 'value', 'data'].forEach(function(key) {
|
||||
var expected = test[key];
|
||||
|
||||
var value = parsedTransaction[key];
|
||||
|
||||
if ({ gasLimit: 1, gasPrice: 1, value: 1 }[key]) {
|
||||
assert.ok((!!value._bn),
|
||||
'parsed into a big number - ' + key);
|
||||
value = value.toHexString();
|
||||
|
||||
if (!expected || expected === '0x') { expected = '0x00'; }
|
||||
|
||||
} else if (key === 'nonce') {
|
||||
assert.equal(typeof(value), 'number',
|
||||
'parse into a number - nonce');
|
||||
|
||||
value = utils.hexlify(value);
|
||||
|
||||
if (!expected || expected === '0x') { expected = '0x00'; }
|
||||
|
||||
} else if (key === 'data') {
|
||||
if (!expected) { expected = '0x'; }
|
||||
|
||||
} else if (key === 'to') {
|
||||
if (value) {
|
||||
// Make sure teh address is valid
|
||||
getAddress(value);
|
||||
value = value.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
assert.equal(value, expected, 'parsed ' + key);
|
||||
|
||||
transaction[key] = test[key];
|
||||
});
|
||||
|
||||
assert.equal(parsedTransaction.from, getAddress(test.accountAddress),
|
||||
'computed from');
|
||||
|
||||
assert.equal(parsedTransaction.chainId, 0, 'parsed chainId');
|
||||
|
||||
var signedTransaction = wallet.sign(transaction);
|
||||
assert.equal(signedTransaction, test.signedTransaction,
|
||||
'signed transaction');
|
||||
|
||||
// EIP155
|
||||
|
||||
var parsedTransactionChainId5 = Wallet.parseTransaction(test.signedTransactionChainId5);
|
||||
['data', 'from', 'nonce', 'to'].forEach(function (key) {
|
||||
assert.equal(parsedTransaction[key], parsedTransactionChainId5[key],
|
||||
'eip155 parsed ' + key);
|
||||
});
|
||||
['gasLimit', 'gasPrice', 'value'].forEach(function (key) {
|
||||
assert.ok(parsedTransaction[key].eq(parsedTransactionChainId5[key]),
|
||||
'eip155 parsed ' + key);
|
||||
});
|
||||
assert.equal(parsedTransactionChainId5.chainId, 5,
|
||||
'eip155 parsed chainId');
|
||||
|
||||
transaction.chainId = 5;
|
||||
var signedTransactionChainId5 = wallet.sign(transaction);
|
||||
assert.equal(signedTransactionChainId5, test.signedTransactionChainId5,
|
||||
'eip155 signed transaction');
|
||||
});
|
||||
});
|
||||
});
|
BIN
tests/tests/accounts.json.gz
Normal file
BIN
tests/tests/accounts.json.gz
Normal file
Binary file not shown.
BIN
tests/tests/contract-interface.json.gz
Normal file
BIN
tests/tests/contract-interface.json.gz
Normal file
Binary file not shown.
BIN
tests/tests/hdnode.json.gz
Normal file
BIN
tests/tests/hdnode.json.gz
Normal file
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
This file just ensures this directory exists.
|
||||
|
||||
Run the files in make-tests to create the individual test cases.
|
BIN
tests/tests/namehash.json.gz
Normal file
BIN
tests/tests/namehash.json.gz
Normal file
Binary file not shown.
BIN
tests/tests/rlp-coder.json.gz
Normal file
BIN
tests/tests/rlp-coder.json.gz
Normal file
Binary file not shown.
BIN
tests/tests/transactions.json.gz
Normal file
BIN
tests/tests/transactions.json.gz
Normal file
Binary file not shown.
BIN
tests/tests/units.json.gz
Normal file
BIN
tests/tests/units.json.gz
Normal file
Binary file not shown.
BIN
tests/tests/wallets.json.gz
Normal file
BIN
tests/tests/wallets.json.gz
Normal file
Binary file not shown.
@ -1,7 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
var crypto = require('crypto');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var zlib = require('zlib');
|
||||
|
||||
//var utils = require('../lib/utils.js');
|
||||
var bigNumber = require('../utils/bignumber');
|
||||
var convert = require('../utils/convert');
|
||||
var keccak256 = require('../utils/keccak256');
|
||||
var utf8 = require('../utils/utf8');
|
||||
|
||||
/*
|
||||
function random(lowerRandomInterval, upperOpenInterval) {
|
||||
return lowerRandomInterval + parseInt((upperOpenInterval - lowerRandomInterval) * Math.random());
|
||||
}
|
||||
@ -14,6 +23,35 @@ function randomBuffer(length) {
|
||||
function randomHexString(length) {
|
||||
return '0x' + randomBuffer(length).toString('hex');
|
||||
}
|
||||
*/
|
||||
function randomBytes(seed, lower, upper) {
|
||||
if (!upper) { upper = lower; }
|
||||
|
||||
if (upper === 0 && upper === lower) { return new Uint8Array(0); }
|
||||
|
||||
seed = utf8.toUtf8Bytes(seed);
|
||||
|
||||
var result = convert.arrayify(keccak256(seed));
|
||||
while (result.length < upper) {
|
||||
result = convert.concat([result, keccak256(convert.concat([seed, result]))]);
|
||||
}
|
||||
|
||||
var top = convert.arrayify(keccak256(result));
|
||||
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
|
||||
|
||||
return result.slice(0, lower + parseInt((upper - lower) * percent));
|
||||
}
|
||||
|
||||
function randomHexString(seed, lower, upper) {
|
||||
return convert.hexlify(randomBytes(seed, lower, upper));
|
||||
}
|
||||
|
||||
function randomNumber(seed, lower, upper) {
|
||||
var top = randomBytes(seed, 3);
|
||||
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
|
||||
return lower + parseInt((upper - lower) * percent);
|
||||
}
|
||||
|
||||
|
||||
function equals(a, b) {
|
||||
|
||||
@ -46,12 +84,32 @@ function equals(a, b) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
random: random,
|
||||
randomBuffer: randomBuffer,
|
||||
randomHexString: randomHexString,
|
||||
equals: equals,
|
||||
function saveTests(tag, data) {
|
||||
var filename = path.resolve(__dirname, 'tests', tag + '.json.gz');
|
||||
|
||||
//isHexString: utils.isHexString,
|
||||
//hexOrBuffer: utils.hexOrBuffer,
|
||||
var data = JSON.stringify(data, undefined, ' ') + '\n';
|
||||
fs.writeFileSync(filename, zlib.gzipSync(data));
|
||||
|
||||
console.log('Save testcase: ' + filename);
|
||||
}
|
||||
|
||||
function loadTests(tag) {
|
||||
var filename = path.resolve(__dirname, 'tests', tag + '.json.gz');
|
||||
return JSON.parse(zlib.gunzipSync(fs.readFileSync(filename)));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
randomBytes: randomBytes,
|
||||
randomHexString: randomHexString,
|
||||
randomNumber:randomNumber,
|
||||
|
||||
bigNumberify: bigNumber.bigNumberify,
|
||||
|
||||
equals: equals,
|
||||
isHexString: convert.isHexString,
|
||||
hexlify: convert.hexlify,
|
||||
arrayify: convert.arrayify,
|
||||
|
||||
loadTests: loadTests,
|
||||
saveTests: saveTests,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user