Review Unit class
* Add 100% code coverage * Add custom error code * Linted source and test * More descriptive test messages
This commit is contained in:
parent
85169a3874
commit
be599e5a1b
|
@ -34,6 +34,13 @@ module.exports = [{
|
|||
}, {
|
||||
name: 'InvalidArgumentType',
|
||||
message: format('Invalid Argument for {2}, expected {1} but got ') + '+ typeof arguments[0]',
|
||||
}, {
|
||||
name: 'Unit',
|
||||
message: format('Internal Error on Unit {0}'),
|
||||
errors: [{
|
||||
'name': 'UnknownCode',
|
||||
'message': format('Unrecognized unit code: {0}')
|
||||
}]
|
||||
}, {
|
||||
name: 'Transaction',
|
||||
message: format('Internal Error on Transaction {0}'),
|
||||
|
|
65
lib/unit.js
65
lib/unit.js
|
@ -1,13 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
var errors = require('./errors');
|
||||
var JSUtil = require('./util/js');
|
||||
|
||||
var UNITS = {
|
||||
'BTC' : [1e8, 8],
|
||||
'mBTC' : [1e5, 5],
|
||||
'uBTC' : [1e2, 2],
|
||||
'bits' : [1e2, 2],
|
||||
'satoshis' : [1, 0]
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Bitcore Unit
|
||||
*
|
||||
* Utility for handling and converting bitcoins units. The supported units are
|
||||
* BTC, mBTC, bits and satoshis. A unit instance can be created with an
|
||||
* BTC, mBTC, bits (also named uBTC) and satoshis. A unit instance can be created with an
|
||||
* amount and a unit code, or alternatively using static methods like {fromBTC}.
|
||||
* You can consult for different representation of a unit instance using it's
|
||||
* {to} method, the fixed unit methods like {toSatoshis} or alternatively using
|
||||
|
@ -15,7 +21,6 @@ var JSUtil = require('./util/js');
|
|||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
*
|
||||
* var sats = Unit.fromBTC(1.3).toSatoshis();
|
||||
* var mili = Unit.fromBits(1.3).to(Unit.mBTC);
|
||||
* var btc = new Unit(1.3, Unit.bits).BTC;
|
||||
|
@ -45,22 +50,14 @@ function Unit(amount, code) {
|
|||
};
|
||||
|
||||
Object.keys(UNITS).forEach(defineAccesor);
|
||||
};
|
||||
|
||||
var UNITS = {
|
||||
'BTC' : [1e8, 8],
|
||||
'mBTC' : [1e5, 5],
|
||||
'uBTC' : [1e2, 2],
|
||||
'bits' : [1e2, 2],
|
||||
'satoshis' : [1, 0]
|
||||
};
|
||||
}
|
||||
|
||||
Object.keys(UNITS).forEach(function(key) {
|
||||
Unit[key] = key;
|
||||
});
|
||||
|
||||
/**
|
||||
* Will return a Unit instance created from JSON string or object
|
||||
* Returns a Unit instance created from JSON string or object
|
||||
*
|
||||
* @param {String|Object} json - JSON with keys: amount and code
|
||||
* @returns {Unit} A Unit instance
|
||||
|
@ -73,7 +70,7 @@ Unit.fromJSON = function fromJSON(json){
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a Unit instance created from an amount in BTC
|
||||
* Returns a Unit instance created from an amount in BTC
|
||||
*
|
||||
* @param {Number} amount - The amount in BTC
|
||||
* @returns {Unit} A Unit instance
|
||||
|
@ -83,7 +80,7 @@ Unit.fromBTC = function(amount) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a Unit instance created from an amount in mBTC
|
||||
* Returns a Unit instance created from an amount in mBTC
|
||||
*
|
||||
* @param {Number} amount - The amount in mBTC
|
||||
* @returns {Unit} A Unit instance
|
||||
|
@ -93,7 +90,7 @@ Unit.fromMilis = function(amount) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a Unit instance created from an amount in bits
|
||||
* Returns a Unit instance created from an amount in bits
|
||||
*
|
||||
* @param {Number} amount - The amount in bits
|
||||
* @returns {Unit} A Unit instance
|
||||
|
@ -103,7 +100,7 @@ Unit.fromMicros = Unit.fromBits = function(amount) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a Unit instance created from an amount in satoshis
|
||||
* Returns a Unit instance created from an amount in satoshis
|
||||
*
|
||||
* @param {Number} amount - The amount in satoshis
|
||||
* @returns {Unit} A Unit instance
|
||||
|
@ -113,26 +110,29 @@ Unit.fromSatoshis = function(amount) {
|
|||
};
|
||||
|
||||
Unit.prototype._from = function(amount, code) {
|
||||
if (!UNITS[code]) throw Error('Unknown unit code');
|
||||
|
||||
if (!UNITS[code]) {
|
||||
throw new errors.Unit.UnknownCode(code);
|
||||
}
|
||||
return parseInt((amount * UNITS[code][0]).toFixed());
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return the value represented in the specified unit
|
||||
* Returns the value represented in the specified unit
|
||||
*
|
||||
* @param {string} code - The unit code
|
||||
* @returns {Number} The converted value
|
||||
*/
|
||||
Unit.prototype.to = function(code) {
|
||||
if (!UNITS[code]) throw Error('Unknown unit code');
|
||||
if (!UNITS[code]) {
|
||||
throw new errors.Unit.UnknownCode(code);
|
||||
}
|
||||
|
||||
var value = this._value / UNITS[code][0];
|
||||
return parseFloat(value.toFixed(UNITS[code][1]));
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return the value represented in BTC
|
||||
* Returns the value represented in BTC
|
||||
*
|
||||
* @returns {Number} The value converted to BTC
|
||||
*/
|
||||
|
@ -141,26 +141,25 @@ Unit.prototype.toBTC = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Will return the value represented in mBTC
|
||||
* Returns the value represented in mBTC
|
||||
*
|
||||
* @returns {Number} The value converted to mBTC
|
||||
*/
|
||||
Unit.prototype.toMilis = function(code) {
|
||||
Unit.prototype.toMilis = function() {
|
||||
return this.to(Unit.mBTC);
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return the value represented in bits
|
||||
* Returns the value represented in bits
|
||||
*
|
||||
* @returns {Number} The value converted to bits
|
||||
*/
|
||||
Unit.prototype.toMicros = Unit.prototype.toBits = function(code) {
|
||||
Unit.prototype.toMicros = Unit.prototype.toBits = function() {
|
||||
return this.to(Unit.bits);
|
||||
};
|
||||
|
||||
/**
|
||||
* Will return the value represented in satoshis
|
||||
* Returns the value represented in satoshis
|
||||
*
|
||||
* @returns {Number} The value converted to satoshis
|
||||
*/
|
||||
|
@ -169,7 +168,7 @@ Unit.prototype.toSatoshis = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a the string representation of the value in satoshis
|
||||
* Returns a the string representation of the value in satoshis
|
||||
*
|
||||
* @returns {String} the value in satoshis
|
||||
*/
|
||||
|
@ -178,7 +177,7 @@ Unit.prototype.toString = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a plain object representation of the Unit
|
||||
* Returns a plain object representation of the Unit
|
||||
*
|
||||
* @returns {Object} An object with the keys: amount and code
|
||||
*/
|
||||
|
@ -194,7 +193,7 @@ Unit.prototype.toJSON = function toJSON() {
|
|||
};
|
||||
|
||||
/**
|
||||
* Will return a string formatted for the console
|
||||
* Returns a string formatted for the console
|
||||
*
|
||||
* @returns {String} the value in satoshis
|
||||
*/
|
||||
|
|
83
test/unit.js
83
test/unit.js
|
@ -1,30 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
var should = require('chai').should();
|
||||
var expect = require('chai').expect;
|
||||
|
||||
var bitcore = require('..');
|
||||
var errors = bitcore.errors;
|
||||
var Unit = bitcore.Unit;
|
||||
|
||||
describe('Unit', function() {
|
||||
|
||||
it('should create an instance', function() {
|
||||
var unit;
|
||||
|
||||
unit = new Unit(1.2, 'BTC');
|
||||
should.exist(unit);
|
||||
|
||||
unit = Unit(1.2, 'BTC');
|
||||
should.exist(unit);
|
||||
it('can be created from a number and unit', function() {
|
||||
expect(function() {
|
||||
return new Unit(1.2, 'BTC');
|
||||
}).to.not.throw();
|
||||
});
|
||||
|
||||
it('should have property accesors', function() {
|
||||
it('no "new" is required for creating an instance', function() {
|
||||
expect(function() {
|
||||
return Unit(1.2, 'BTC');
|
||||
}).to.not.throw();
|
||||
});
|
||||
|
||||
it('has property accesors "BTC", "mBTC", "uBTC", "bits", and "satoshis"', function() {
|
||||
var unit = new Unit(1.2, 'BTC');
|
||||
should.exist(unit.BTC);
|
||||
should.exist(unit.mBTC);
|
||||
should.exist(unit.bits);
|
||||
should.exist(unit.satoshis);
|
||||
unit.BTC.should.equal(1.2);
|
||||
unit.mBTC.should.equal(1200);
|
||||
unit.uBTC.should.equal(1200000);
|
||||
unit.bits.should.equal(1200000);
|
||||
unit.satoshis.should.equal(120000000);
|
||||
});
|
||||
|
||||
it('should allow amount as string', function() {
|
||||
it('a string amount is allowed', function() {
|
||||
var unit;
|
||||
|
||||
unit = Unit.fromBTC('1.00001');
|
||||
|
@ -56,7 +62,8 @@ describe('Unit', function() {
|
|||
unit.satoshis.should.equal(8999);
|
||||
});
|
||||
|
||||
it('should convert to satoshis correctly', function() {
|
||||
it('converts to satoshis correctly', function() {
|
||||
/* jshint maxstatements: 25 */
|
||||
var unit;
|
||||
|
||||
unit = Unit.fromBTC(1.3);
|
||||
|
@ -80,14 +87,14 @@ describe('Unit', function() {
|
|||
unit.bits.should.equal(0.03);
|
||||
});
|
||||
|
||||
it('should take in count floating point problems', function() {
|
||||
it('takes into account floating point problems', function() {
|
||||
var unit = Unit.fromBTC(0.00000003);
|
||||
unit.mBTC.should.equal(0.00003);
|
||||
unit.bits.should.equal(0.03);
|
||||
unit.satoshis.should.equal(3);
|
||||
});
|
||||
|
||||
it('should expose unit codes', function() {
|
||||
it('exposes unit codes', function() {
|
||||
should.exist(Unit.BTC);
|
||||
Unit.BTC.should.equal('BTC');
|
||||
|
||||
|
@ -101,15 +108,7 @@ describe('Unit', function() {
|
|||
Unit.satoshis.should.equal('satoshis');
|
||||
});
|
||||
|
||||
it('should expose shorthand conversion methods', function() {
|
||||
var unit = new Unit(1.3, 'BTC');
|
||||
unit.toBTC().should.equal(unit.BTC);
|
||||
unit.toMilis().should.equal(unit.mBTC);
|
||||
unit.toBits().should.equal(unit.bits);
|
||||
unit.toSatoshis().should.equal(unit.satoshis);
|
||||
});
|
||||
|
||||
it('should expose a general conversion method', function() {
|
||||
it('exposes a method that converts to different units', function() {
|
||||
var unit = new Unit(1.3, 'BTC');
|
||||
unit.to(Unit.BTC).should.equal(unit.BTC);
|
||||
unit.to(Unit.mBTC).should.equal(unit.mBTC);
|
||||
|
@ -117,22 +116,44 @@ describe('Unit', function() {
|
|||
unit.to(Unit.satoshis).should.equal(unit.satoshis);
|
||||
});
|
||||
|
||||
it('should have a toString method', function() {
|
||||
it('exposes shorthand conversion methods', function() {
|
||||
var unit = new Unit(1.3, 'BTC');
|
||||
unit.toBTC().should.equal(unit.BTC);
|
||||
unit.toMilis().should.equal(unit.mBTC);
|
||||
unit.toBits().should.equal(unit.bits);
|
||||
unit.toSatoshis().should.equal(unit.satoshis);
|
||||
});
|
||||
|
||||
it('toString works as expected', function() {
|
||||
var unit = new Unit(1.3, 'BTC');
|
||||
should.exist(unit.toString);
|
||||
unit.toString().should.be.a('string');
|
||||
});
|
||||
|
||||
it('should input/output JSON', function() {
|
||||
it('can be imported and exported from/to JSON', function() {
|
||||
var json = JSON.stringify({amount:1.3, code:'BTC'});
|
||||
var unit = Unit.fromJSON(json);
|
||||
unit.toJSON().should.deep.equal(json);
|
||||
});
|
||||
|
||||
it('should have an inspect method', function() {
|
||||
it('importing from invalid JSON fails quickly', function() {
|
||||
expect(function() {
|
||||
return Unit.fromJSON('¹');
|
||||
}).to.throw();
|
||||
});
|
||||
|
||||
it('inspect method displays nicely', function() {
|
||||
var unit = new Unit(1.3, 'BTC');
|
||||
should.exist(unit.inspect);
|
||||
unit.inspect().should.be.a('string');
|
||||
unit.inspect().should.equal('<Unit: 130000000 satoshis>');
|
||||
});
|
||||
|
||||
it('fails when the unit is not recognized', function() {
|
||||
expect(function() {
|
||||
return new Unit(100, 'USD');
|
||||
}).to.throw(errors.Unit.UnknownCode);
|
||||
expect(function() {
|
||||
return new Unit(100, 'BTC').to('USD');
|
||||
}).to.throw(errors.Unit.UnknownCode);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue