From 2a55c900cef15176cbb92756c7709501c56854ca Mon Sep 17 00:00:00 2001 From: Patrick Nagurny Date: Thu, 30 Jul 2015 17:45:55 -0400 Subject: [PATCH] update tests --- lib/modules/address.js | 3 +- test/modules/address.unit.js | 200 ++++++++++++++++++++++++++++++----- test/transaction.unit.js | 9 +- 3 files changed, 178 insertions(+), 34 deletions(-) diff --git a/lib/modules/address.js b/lib/modules/address.js index 81d5d727..c4a582f8 100644 --- a/lib/modules/address.js +++ b/lib/modules/address.js @@ -346,7 +346,6 @@ AddressModule.prototype.getAddressHistory = function(address, queryMempool, call }); } - this.getOutputs(address, queryMempool, function(err, outputs) { if(err) { return callback(err); @@ -395,7 +394,7 @@ AddressModule.prototype.getAddressHistory = function(address, queryMempool, call // sort by height history.sort(function(a, b) { - return a.height < b.height; + return a.height > b.height; }); callback(null, history); diff --git a/test/modules/address.unit.js b/test/modules/address.unit.js index 40d5fa68..a4b2d0ab 100644 --- a/test/modules/address.unit.js +++ b/test/modules/address.unit.js @@ -8,6 +8,8 @@ var blockData = require('../data/livenet-345003.json'); var bitcore = require('bitcore'); var EventEmitter = require('events').EventEmitter; var errors = bitcoindjs.errors; +var chainlib = require('chainlib'); +var levelup = chainlib.deps.levelup; describe('AddressModule', function() { @@ -15,7 +17,7 @@ describe('AddressModule', function() { it('should return the correct methods', function() { var am = new AddressModule({}); var methods = am.getAPIMethods(); - methods.length.should.equal(6); + methods.length.should.equal(5); }); }); @@ -119,7 +121,7 @@ describe('AddressModule', function() { operations[3].type.should.equal('put'); var expected3 = ['sp', key3.prevTxId, key3.prevOutputIndex].join('-'); operations[3].key.should.equal(expected3); - operations[3].value.should.equal([value3.txid].join(':')); + operations[3].value.should.equal([value3.txid, value3.inputIndex].join(':')); operations[64].type.should.equal('put'); var expected64 = ['outs', key64.address, key64.timestamp, key64.txid, key64.outputIndex].join('-'); operations[64].key.should.equal(expected64); @@ -136,7 +138,7 @@ describe('AddressModule', function() { operations[0].value.should.equal([value0.satoshis, value0.script, value0.blockHeight].join(':')); operations[3].type.should.equal('del'); operations[3].key.should.equal(['sp', key3.prevTxId, key3.prevOutputIndex].join('-')); - operations[3].value.should.equal([value3.txid].join(':')); + operations[3].value.should.equal([value3.txid, value3.inputIndex].join(':')); operations[64].type.should.equal('del'); operations[64].key.should.equal(['outs', key64.address, key64.timestamp, key64.txid, key64.outputIndex].join('-')); operations[64].value.should.equal([value64.satoshis, value64.script, value64.blockHeight].join(':')); @@ -495,66 +497,208 @@ describe('AddressModule', function() { }); }); - describe('#getSpendTxForOutput', function() { - it('should call store.get and db.getTransaction with the right values', function(done) { + describe('#getSpendInfoForOutput', function() { + it('should call store.get the right values', function(done) { var db = { store: { - get: sinon.stub().callsArgWith(1, null, 'spendtxid') - }, - getTransaction: sinon.stub().callsArgWith(2, null, 'spendtx') + get: sinon.stub().callsArgWith(1, null, 'spendtxid:1') + } }; var am = new AddressModule({db: db}); - am.getSpendTxForOutput('txid', 'outputindex', true, function(err, tx) { + am.getSpendInfoForOutput('txid', 3, function(err, info) { should.not.exist(err); - tx.should.equal('spendtx'); - db.store.get.args[0][0].should.equal('sp-txid-outputindex'); - db.getTransaction.args[0][0].should.equal('spendtxid'); - db.getTransaction.args[0][1].should.equal(true); + info.txid.should.equal('spendtxid'); + info.inputIndex.should.equal('1'); + db.store.get.args[0][0].should.equal('sp-txid-3'); done(); }); }); }); - describe('#getTransactionsForAddress', function() { - var outputs = [ + describe('#getAddressHistory', function() { + var incoming = [ { txid: 'tx1', outputIndex: 0, - spentTx: 'tx2' + spentTx: 'tx2', + inputIndex: 0, + height: 1, + timestamp: 1438289011844, + satoshis: 5000 }, { txid: 'tx3', - outputIndex: 1 + outputIndex: 1, + height: 3, + timestamp: 1438289031844, + satoshis: 2000 }, { txid: 'tx4', outputIndex: 2, - spentTx: 'tx5' + spentTx: 'tx5', + inputIndex: 1, + height: 4, + timestamp: 1438289041844, + satoshis: 3000 + }, + ]; + + var outgoing = [ + { + txid: 'tx2', + height: 2, + timestamp: 1438289021844, + inputs: [ + { + output: { + satoshis: 5000 + } + } + ] + }, + { + txid: 'tx5', + height: 5, + timestamp: 1438289051844, + inputs: [ + {}, + { + output: { + satoshis: 3000 + } + } + ] } ]; var db = { - getTransaction: function(txid, queryMempool, callback) { - callback(null, txid); + getTransactionWithBlockInfo: function(txid, queryMempool, callback) { + var transaction = { + populateInputs: sinon.stub().callsArg(2) + }; + for(var i = 0; i < incoming.length; i++) { + if(incoming[i].txid === txid) { + if(incoming[i].error) { + return callback(new Error(incoming[i].error)); + } + transaction.hash = txid; + transaction.__height = incoming[i].height; + transaction.__timestamp = incoming[i].timestamp; + return callback(null, transaction); + } + } + + for(var i = 0; i < outgoing.length; i++) { + if(outgoing[i].txid === txid) { + if(outgoing[i].error) { + return callback(new Error(outgoing[i].error)); + } + transaction.hash = txid; + transaction.__height = outgoing[i].height; + transaction.__timestamp = outgoing[i].timestamp; + transaction.inputs = outgoing[i].inputs; + return callback(null, transaction); + } + } + callback(new Error('tx ' + txid + ' not found')); } }; var am = new AddressModule({db: db}); - am.getOutputs = sinon.stub().callsArgWith(2, null, outputs); - am.getSpendTxForOutput = function(txid, outputIndex, queryMempool, callback) { - for(var i = 0; i < outputs.length; i++) { - if(outputs[i].txid === txid && outputs[i].outputIndex === outputIndex && outputs[i].spentTx) { - return callback(null, outputs[i].spentTx); + am.getOutputs = sinon.stub().callsArgWith(2, null, incoming); + am.getSpendInfoForOutput = function(txid, outputIndex, callback) { + for(var i = 0; i < incoming.length; i++) { + if(incoming[i].txid === txid && incoming[i].outputIndex === outputIndex && incoming[i].spentTx) { + if(incoming[i].spendError) { + return callback(new Error(incoming[i].spendError)); + } + return callback(null, { + txid: incoming[i].spentTx, + inputIndex: incoming[i].inputIndex + }); } } callback(new levelup.errors.NotFoundError()); }; - it('should give transactions containing address as an output and an input', function(done) { - am.getTransactionsForAddress('address', true, function(err, txs) { + it('should give transaction history for an address', function(done) { + am.getAddressHistory('address', true, function(err, history) { should.not.exist(err); - txs.should.deep.equal(['tx1', 'tx2', 'tx3', 'tx4', 'tx5']); + console.log(history); + history[0].transaction.hash.should.equal('tx1'); + history[0].satoshis.should.equal(5000); + history[0].height.should.equal(1); + history[0].timestamp.should.equal(1438289011844); + history[1].transaction.hash.should.equal('tx2'); + history[1].satoshis.should.equal(-5000); + history[1].height.should.equal(2); + history[1].timestamp.should.equal(1438289021844); + history[2].transaction.hash.should.equal('tx3'); + history[2].satoshis.should.equal(2000); + history[2].height.should.equal(3); + history[2].timestamp.should.equal(1438289031844); + history[3].transaction.hash.should.equal('tx4'); + history[3].satoshis.should.equal(3000); + history[3].height.should.equal(4); + history[3].timestamp.should.equal(1438289041844); + history[4].transaction.hash.should.equal('tx5'); + history[4].satoshis.should.equal(-3000); + history[4].height.should.equal(5); + history[4].timestamp.should.equal(1438289051844); + done(); + }); + }); + + it('should give an error if the second getTransactionInfo gives an error', function(done) { + outgoing[0].error = 'txinfo2err'; + am.getAddressHistory('address', true, function(err, history) { + should.exist(err); + err.message.should.equal('txinfo2err'); + outgoing[0].error = null; + done(); + }); + }); + + it('should give an error if getSpendInfoForOutput gives an error', function(done) { + incoming[0].spendError = 'spenderr'; + am.getAddressHistory('address', true, function(err, history) { + should.exist(err); + err.message.should.equal('spenderr'); + incoming[0].spendError = null; + done(); + }); + }); + + it('should give an error if the first getTransactionInfo gives an error', function(done) { + incoming[1].error = 'txinfo1err'; + am.getAddressHistory('address', true, function(err, history) { + should.exist(err); + err.message.should.equal('txinfo1err'); + incoming[1].error = null; + done(); + }); + }); + + it('should give an error if populateInputs gives an error', function(done) { + var populateStub = sinon.stub().callsArgWith(2, new Error('populateerr')); + sinon.stub(db, 'getTransactionWithBlockInfo').callsArgWith(2, null, { + populateInputs: populateStub + }); + am.getAddressHistory('address', true, function(err, history) { + should.exist(err); + err.message.should.equal('populateerr'); + db.getTransactionWithBlockInfo.restore(); + done(); + }); + }); + + it('should give an error if getOutputs gives an error', function(done) { + am.getOutputs = sinon.stub().callsArgWith(2, new Error('getoutputserr')); + am.getAddressHistory('address', true, function(err, history) { + should.exist(err); + err.message.should.equal('getoutputserr'); done(); }); }); diff --git a/test/transaction.unit.js b/test/transaction.unit.js index cb3d56ab..9f02ba74 100644 --- a/test/transaction.unit.js +++ b/test/transaction.unit.js @@ -106,6 +106,7 @@ describe('Bitcoin Transaction', function() { describe('#populateInputs', function() { it('will call _populateInput with transactions', function() { var tx = new Transaction(); + tx.isCoinbase = sinon.stub().returns(false); tx._populateInput = sinon.stub().callsArg(3); tx.inputs = ['input']; var transactions = []; @@ -138,7 +139,7 @@ describe('Bitcoin Transaction', function() { it('if an error happened it should pass it along', function(done) { var tx = new Transaction(); var db = { - getTransactionFromDB: sinon.stub().callsArgWith(1, new Error('error')) + getTransaction: sinon.stub().callsArgWith(2, new Error('error')) }; tx._populateInput(db, input, [], function(err) { should.exist(err); @@ -149,7 +150,7 @@ describe('Bitcoin Transaction', function() { it('should return an error if the transaction for the input does not exist', function(done) { var tx = new Transaction(); var db = { - getTransactionFromDB: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError()) + getTransaction: sinon.stub().callsArgWith(2, new levelup.errors.NotFoundError()) }; tx._populateInput(db, input, [], function(err) { should.exist(err); @@ -160,7 +161,7 @@ describe('Bitcoin Transaction', function() { it('should look through poolTransactions if database does not have transaction', function(done) { var tx = new Transaction(); var db = { - getTransactionFromDB: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError()) + getTransaction: sinon.stub().callsArgWith(2, new levelup.errors.NotFoundError()) }; var transactions = [ { @@ -179,7 +180,7 @@ describe('Bitcoin Transaction', function() { prevTx.outputs = ['output']; var tx = new Transaction(); var db = { - getTransactionFromDB: sinon.stub().callsArgWith(1, null, prevTx) + getTransaction: sinon.stub().callsArgWith(2, null, prevTx) }; tx._populateInput(db, input, [], function(err) { should.not.exist(err);