From afb5b6971f6f9a072e36955d7663fc741513fb8f Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Wed, 17 Dec 2014 10:31:38 -0300 Subject: [PATCH 1/3] Add tests for bufferutils --- lib/util/buffer.js | 10 +++ lib/util/preconditions.js | 3 + test/util/buffer.js | 161 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 test/util/buffer.js diff --git a/lib/util/buffer.js b/lib/util/buffer.js index f7de3cd..62a3222 100644 --- a/lib/util/buffer.js +++ b/lib/util/buffer.js @@ -4,6 +4,7 @@ var buffer = require('buffer'); var assert = require('assert'); var js = require('./js'); +var $ = require('./preconditions'); function equals(a, b) { if (a.length !== b.length) { @@ -27,6 +28,8 @@ module.exports = { * @return {Buffer} */ fill: function fill(buffer, value) { + $.checkArgumentType(buffer, Buffer, 'buffer'); + $.checkArgumentType(value, 'number', 'value'); var length = buffer.length; for (var i = 0; i < length; i++) { buffer[i] = value; @@ -52,6 +55,7 @@ module.exports = { * @return {Buffer} */ emptyBuffer: function emptyBuffer(bytes) { + $.checkArgumentType(bytes, 'number', 'bytes'); var result = new buffer.Buffer(bytes); for (var i = 0; i < bytes; i++) { result.write('\0', i); @@ -76,6 +80,7 @@ module.exports = { * @return {Buffer} */ integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) { + $.checkArgumentType(integer, 'number', 'integer'); return new buffer.Buffer([integer & 0xff]); }, @@ -86,6 +91,7 @@ module.exports = { * @return {Buffer} */ integerAsBuffer: function integerAsBuffer(integer) { + $.checkArgumentType(integer, 'number', 'integer'); var bytes = []; bytes.push((integer >> 24) & 0xff); bytes.push((integer >> 16) & 0xff); @@ -101,6 +107,7 @@ module.exports = { * @return {number} */ integerFromBuffer: function integerFromBuffer(buffer) { + $.checkArgumentType(buffer, Buffer, 'buffer'); return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; }, @@ -110,6 +117,7 @@ module.exports = { * @return {number} */ integerFromSingleByteBuffer: function integerFromBuffer(buffer) { + $.checkArgumentType(buffer, Buffer, 'buffer'); return buffer[0]; }, @@ -122,6 +130,7 @@ module.exports = { * @return {string} */ bufferToHex: function bufferToHex(buffer) { + $.checkArgumentType(buffer, Buffer, 'buffer'); return buffer.toString('hex'); }, @@ -131,6 +140,7 @@ module.exports = { * @return {Buffer} */ reverse: function reverse(param) { + $.checkArgumentType(param, Buffer, 'param'); var ret = new buffer.Buffer(param.length); for (var i = 0; i < param.length; i++) { ret[i] = param[param.length - i - 1]; diff --git a/lib/util/preconditions.js b/lib/util/preconditions.js index 434a306..9e87b5d 100644 --- a/lib/util/preconditions.js +++ b/lib/util/preconditions.js @@ -17,6 +17,9 @@ module.exports = { checkArgumentType: function(argument, type, argumentName) { argumentName = argumentName || '(unknown name)'; if (_.isString(type)) { + if (type === 'number' && !_.isNumber(argument)) { + throw new errors.InvalidArgumentType(argument, type, argumentName); + } if (typeof argument !== type) { throw new errors.InvalidArgumentType(argument, type, argumentName); } diff --git a/test/util/buffer.js b/test/util/buffer.js new file mode 100644 index 0000000..04e0582 --- /dev/null +++ b/test/util/buffer.js @@ -0,0 +1,161 @@ +'use strict'; +/* jshint unused: false */ + +var should = require('chai').should(); +var expect = require('chai').expect; + +var bitcore = require('../..'); +var errors = bitcore.errors; +var BufferUtil = bitcore.util.buffer; + +describe('buffer utils', function() { + + describe('equals', function() { + it('recognizes these two equal buffers', function() { + var bufferA = new Buffer([1, 2, 3]); + var bufferB = new Buffer('010203', 'hex'); + BufferUtil.equal(bufferA, bufferB).should.equal(true); + }); + it('no false positive: returns false with two different buffers', function() { + var bufferA = new Buffer([1, 2, 3]); + var bufferB = new Buffer('010204', 'hex'); + BufferUtil.equal(bufferA, bufferB).should.equal(false); + }); + it('coverage: quickly realizes a difference in size and returns false', function() { + var bufferA = new Buffer([1, 2, 3]); + var bufferB = new Buffer([]); + BufferUtil.equal(bufferA, bufferB).should.equal(false); + }); + it('"equals" is an an alias for "equal"', function() { + var bufferA = new Buffer([1, 2, 3]); + var bufferB = new Buffer([1, 2, 3]); + BufferUtil.equal(bufferA, bufferB).should.equal(true); + BufferUtil.equals(bufferA, bufferB).should.equal(true); + }); + }); + + describe('fill', function() { + it('checks arguments', function() { + expect(function() { + BufferUtil.fill('something'); + }).to.throw(errors.InvalidArgumentType); + expect(function() { + BufferUtil.fill(new Buffer([0, 0, 0]), 'invalid'); + }).to.throw(errors.InvalidArgumentType); + }); + it('works correctly for a small buffer', function() { + var buffer = BufferUtil.fill(new Buffer(10), 6); + for (var i = 0; i < 10; i++) { + buffer[i].should.equal(6); + } + }); + }); + + describe('isBuffer', function() { + it('has no false positive', function() { + expect(BufferUtil.isBuffer(1)).to.equal(false); + }); + it('has no false negative', function() { + expect(BufferUtil.isBuffer(new Buffer(0))).to.equal(true); + }); + }); + + describe('emptyBuffer', function() { + it('creates a buffer filled with zeros', function() { + var buffer = BufferUtil.emptyBuffer(10); + expect(buffer.length).to.equal(10); + for (var i = 0; i < 10; i++) { + expect(buffer[i]).to.equal(0); + } + }); + it('checks arguments', function() { + expect(function() { + BufferUtil.emptyBuffer('invalid'); + }).to.throw(errors.InvalidArgumentType); + }); + }); + + describe('single byte buffer <=> integer', function() { + it('integerAsSingleByteBuffer should return a buffer of length 1', function() { + expect(BufferUtil.integerAsSingleByteBuffer(100)[0]).to.equal(100); + }); + it('should check the type', function() { + expect(function() { + BufferUtil.integerAsSingleByteBuffer('invalid'); + }).to.throw(errors.InvalidArgumentType); + expect(function() { + BufferUtil.integerFromSingleByteBuffer('invalid'); + }).to.throw(errors.InvalidArgumentType); + }); + it('works correctly for edge cases', function() { + expect(BufferUtil.integerAsSingleByteBuffer(255)[0]).to.equal(255); + expect(BufferUtil.integerAsSingleByteBuffer(-1)[0]).to.equal(255); + }); + it('does a round trip', function() { + expect(BufferUtil.integerAsSingleByteBuffer( + BufferUtil.integerFromSingleByteBuffer(new Buffer([255])) + )[0]).to.equal(255); + }); + }); + + describe('4byte buffer integer <=> integer', function() { + it('integerAsBuffer should return a buffer of length 4', function() { + expect(BufferUtil.integerAsBuffer(100).length).to.equal(4); + }); + it('is little endian', function() { + expect(BufferUtil.integerAsBuffer(100)[3]).to.equal(100); + }); + it('should check the type', function() { + expect(function() { + BufferUtil.integerAsBuffer('invalid'); + }).to.throw(errors.InvalidArgumentType); + expect(function() { + BufferUtil.integerFromBuffer('invalid'); + }).to.throw(errors.InvalidArgumentType); + }); + it('works correctly for edge cases', function() { + expect(BufferUtil.integerAsBuffer(4294967295)[0]).to.equal(255); + expect(BufferUtil.integerAsBuffer(4294967295)[3]).to.equal(255); + expect(BufferUtil.integerAsBuffer(-1)[0]).to.equal(255); + expect(BufferUtil.integerAsBuffer(-1)[3]).to.equal(255); + }); + it('does a round trip', function() { + expect(BufferUtil.integerFromBuffer( + BufferUtil.integerAsBuffer(10000) + )).to.equal(10000); + }); + }); + + describe('buffer to hex', function() { + it('returns an expected value in hexa', function() { + expect(BufferUtil.bufferToHex(new Buffer([255, 0, 128]))).to.equal('ff0080'); + }); + it('checks the argument type', function() { + expect(function() { + BufferUtil.bufferToHex('invalid'); + }).to.throw(errors.InvalidArgumentType); + }); + it('round trips', function() { + var original = new Buffer([255, 0, 128]); + var hexa = BufferUtil.bufferToHex(original); + var back = BufferUtil.hexToBuffer(hexa); + expect(BufferUtil.equal(original, back)).to.equal(true); + }); + }); + + describe('reverse', function() { + it('reverses a buffer', function() { + // http://bit.ly/1J2Ai4x + var original = new Buffer([255, 0, 128]); + var reversed = BufferUtil.reverse(original); + original[0].should.equal(reversed[2]); + original[1].should.equal(reversed[1]); + original[2].should.equal(reversed[0]); + }); + it('checks the argument type', function() { + expect(function() { + BufferUtil.reverse('invalid'); + }).to.throw(errors.InvalidArgumentType); + }); + }); +}); From c793559fa97b5de904001b45464ed551bc9179b9 Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Wed, 17 Dec 2014 12:31:04 -0300 Subject: [PATCH 2/3] Fix bug on HD*Keys --- lib/hdprivatekey.js | 2 +- lib/hdpublickey.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/hdprivatekey.js b/lib/hdprivatekey.js index 0b157c3..69ed415 100644 --- a/lib/hdprivatekey.js +++ b/lib/hdprivatekey.js @@ -221,7 +221,7 @@ HDPrivateKey.prototype._buildFromObject = function(arg) { // TODO: Type validation var buffers = { version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version, - depth: BufferUtil.integerAsSingleByteBuffer(arg.depth), + depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, diff --git a/lib/hdpublickey.js b/lib/hdpublickey.js index fa00708..8599556 100644 --- a/lib/hdpublickey.js +++ b/lib/hdpublickey.js @@ -231,9 +231,9 @@ HDPublicKey.prototype._buildFromObject = function (arg) { // TODO: Type validation var buffers = { version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version, - depth: BufferUtil.integerAsSingleByteBuffer(arg.depth), + depth: _.isNumber(arg.depth) ? BufferUtil.integerAsSingleByteBuffer(arg.depth) : arg.depth, parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, - childIndex: BufferUtil.integerAsBuffer(arg.childIndex), + childIndex: _.isNumber(arg.childIndex) ? BufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex, chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, publicKey: _.isString(arg.publicKey) ? BufferUtil.hexToBuffer(arg.publicKey) : BufferUtil.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(), From 12cac0e33d1dd17564d317ff0a87e91a96cd8f1f Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Wed, 17 Dec 2014 12:38:56 -0300 Subject: [PATCH 3/3] Fix tests on browsers: need to add Buffer exception --- lib/util/buffer.js | 10 +++++----- lib/util/preconditions.js | 10 ++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/util/buffer.js b/lib/util/buffer.js index 62a3222..f750b5e 100644 --- a/lib/util/buffer.js +++ b/lib/util/buffer.js @@ -28,7 +28,7 @@ module.exports = { * @return {Buffer} */ fill: function fill(buffer, value) { - $.checkArgumentType(buffer, Buffer, 'buffer'); + $.checkArgumentType(buffer, 'Buffer', 'buffer'); $.checkArgumentType(value, 'number', 'value'); var length = buffer.length; for (var i = 0; i < length; i++) { @@ -107,7 +107,7 @@ module.exports = { * @return {number} */ integerFromBuffer: function integerFromBuffer(buffer) { - $.checkArgumentType(buffer, Buffer, 'buffer'); + $.checkArgumentType(buffer, 'Buffer', 'buffer'); return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; }, @@ -117,7 +117,7 @@ module.exports = { * @return {number} */ integerFromSingleByteBuffer: function integerFromBuffer(buffer) { - $.checkArgumentType(buffer, Buffer, 'buffer'); + $.checkArgumentType(buffer, 'Buffer', 'buffer'); return buffer[0]; }, @@ -130,7 +130,7 @@ module.exports = { * @return {string} */ bufferToHex: function bufferToHex(buffer) { - $.checkArgumentType(buffer, Buffer, 'buffer'); + $.checkArgumentType(buffer, 'Buffer', 'buffer'); return buffer.toString('hex'); }, @@ -140,7 +140,7 @@ module.exports = { * @return {Buffer} */ reverse: function reverse(param) { - $.checkArgumentType(param, Buffer, 'param'); + $.checkArgumentType(param, 'Buffer', 'param'); var ret = new buffer.Buffer(param.length); for (var i = 0; i < param.length; i++) { ret[i] = param[param.length - i - 1]; diff --git a/lib/util/preconditions.js b/lib/util/preconditions.js index 9e87b5d..1b80eee 100644 --- a/lib/util/preconditions.js +++ b/lib/util/preconditions.js @@ -17,10 +17,12 @@ module.exports = { checkArgumentType: function(argument, type, argumentName) { argumentName = argumentName || '(unknown name)'; if (_.isString(type)) { - if (type === 'number' && !_.isNumber(argument)) { - throw new errors.InvalidArgumentType(argument, type, argumentName); - } - if (typeof argument !== type) { + if (type === 'Buffer') { + var BufferUtil = require('./buffer'); + if (!BufferUtil.isBuffer(argument)) { + throw new errors.InvalidArgumentType(argument, type, argumentName); + } + } else if (typeof argument !== type) { throw new errors.InvalidArgumentType(argument, type, argumentName); } } else {