Implement bitfields. Add tests for utils datatypes

This commit is contained in:
roblabla 2015-09-09 22:38:03 +00:00
parent 71c93bb3d6
commit b255eaadd1
3 changed files with 275 additions and 1 deletions

View File

@ -9,7 +9,7 @@
},
"scripts": {
"prepublish": "gulp",
"test": "mocha --recursive --require source-map-support/register --reporter spec"
"test": "mocha --recursive --require intelli-espower-loader --require source-map-support/register --reporter spec"
},
"keywords": [
"minecraft",
@ -34,8 +34,10 @@
"gulp-babel": "^5.1.0",
"gulp-plumber": "^1.0.1",
"gulp-sourcemaps": "^1.3.0",
"intelli-espower-loader": "^1.0.0",
"mkdirp": "~0.3.4",
"mocha": "~1.8.2",
"power-assert": "^1.0.0",
"rimraf": "~2.1.1",
"source-map-support": "^0.3.2",
"zfill": "0.0.1"

View File

@ -8,6 +8,7 @@ module.exports = {
'string': [readString, writeString, sizeOfString],
'buffer': [readBuffer, writeBuffer, sizeOfBuffer],
'void': [readVoid, writeVoid, 0],
'bitfield': [readBitField, writeBitField, sizeOfBitField]
};
function readVarInt(buffer, offset) {
@ -143,3 +144,69 @@ function readVoid() {
function writeVoid(value, buffer, offset) {
return offset;
}
function generateBitMask(n) {
return (1 << n) - 1;
}
function readBitField(buffer, offset, typeArgs, context) {
var beginOffset = offset;
var curVal = null;
var bits = 0;
var results = {};
results.value = typeArgs.reduce(function(acc, item) {
var size = item.size;
var val = 0;
while (size > 0) {
if (bits == 0) {
curVal = buffer[offset++];
bits = 8;
}
var bitsToRead = Math.min(size, bits);
val = (val << bitsToRead) | (curVal & generateBitMask(bits)) >> (bits - bitsToRead);
bits -= bitsToRead;
size -= bitsToRead;
}
if (item.signed && val >= 1 << (item.size - 1))
val -= 1 << item.size;
acc[item.name] = val;
return acc;
}, {});
results.size = offset - beginOffset;
return results;
}
function writeBitField(value, buffer, offset, typeArgs, context) {
var toWrite = 0;
var bits = 0;
typeArgs.forEach(function(item) {
var val = value[item.name];
var size = item.size;
var signed = item.signed;
if ((!item.signed && val < 0) || (item.signed && val < -(1 << (size - 1))))
throw new Error(value + " < " + item.signed ? (-(1 << (size - 1))) : 0);
else if ((!item.signed && val >= 1 << size)
|| (item.signed && val >= (1 << (size - 1)) - 1))
throw new Error(value + " >= " + iteme.signed ? (1 << size) : ((1 << (size - 1)) - 1));
while (size > 0) {
var writeBits = Math.min(8 - bits, size);
toWrite = toWrite << writeBits |
((val >> (size - writeBits)) & generateBitMask(writeBits));
size -= writeBits;
bits += writeBits;
if (bits === 8) {
buffer[offset++] = toWrite;
bits = 0;
toWrite = 0;
}
}
});
if (bits != 0)
buffer[offset++] = toWrite << (8 - bits);
return offset;
}
function sizeOfBitField(value, typeArgs, context) {
return Math.ceil(typeArgs.reduce(function(acc, item) {
return acc + item.size;
}, 0) / 8);
}

205
test/dataTypes/utils.js Normal file
View File

@ -0,0 +1,205 @@
var assert = require('power-assert');
var expect = require('chai').expect;
var utils = require('../../dist/datatypes/utils');
var getReader = function(dataType) { return dataType[0]; };
var getWriter = function(dataType) { return dataType[1]; };
var getSizeOf = function(dataType) { return dataType[2]; };
describe('Utils', function() {
describe('.bool', function() {
it('Reads false value for binary 0', function() {
assert.deepEqual(getReader(utils.bool)(new Buffer([0]), 0), {value: false, size: 1});
});
it('Reads true for every other binary value', function() {
var buf = new Buffer([0]);
var i = 1;
while (i < 256) {
buf[0] = i++;
assert.deepEqual(getReader(utils.bool)(buf, 0), {value: true, size: 1});
}
});
it('Writes false', function() {
var buffer = new Buffer(1);
getWriter(utils.bool)(false, buffer, 0);
assert.deepEqual(buffer, new Buffer([0]));
});
it('Writes true', function() {
var buffer = new Buffer(1);
getWriter(utils.bool)(true, buffer, 0);
assert.notDeepEqual(buffer, new Buffer([0]));
});
it('Has a size of 1', function() {
assert.equal(typeof getSizeOf(utils.bool), "number");
assert.equal(getSizeOf(utils.bool), 1);
});
});
describe('.varint', function() {
it.skip('Has no tests', function() {
});
});
describe('.buffer', function() {
it.skip('Has no tests', function() {
});
});
describe('.string', function() {
it.skip('Has no tests', function() {
});
});
describe('.void', function() {
it.skip('Has no tests', function() {
});
});
describe('.bitfield', function() {
it('Reads an unsigned 8 bit number', function() {
var buf = new Buffer([0xff]);
var typeArgs = [
{ "name": "one", "size": 8, "signed": false }
];
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
value: { "one": 255 },
size: 1
});
});
it('Reads a signed 8 bit number', function() {
var buf = new Buffer([0xff]);
var typeArgs = [
{ "name": "one", "size": 8, "signed": true }
];
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
value: { "one": -1 },
size: 1
});
});
it('Reads multiple signed 8 bit numbers', function() {
var buf = new Buffer([0xff, 0x80, 0x12]);
var typeArgs = [
{ "name": "one", "size": 8, "signed": true },
{ "name": "two", "size": 8, "signed": true },
{ "name": "three", "size": 8, "signed": true }
];
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
value: { "one": -1, "two": -128, "three": 18 },
size: 3
});
});
it('Reads multiple unsigned 4 bit numbers', function() {
var buf = new Buffer([0xff, 0x80]);
var typeArgs = [
{ "name": "one", "size": 4, "signed": false },
{ "name": "two", "size": 4, "signed": false },
{ "name": "three", "size": 4, "signed": false }
];
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
value: { "one": 15, "two": 15, "three": 8 },
size: 2
});
});
it('Reads multiple signed 4 bit numbers', function() {
var buf = new Buffer([0xff, 0x80]);
var typeArgs = [
{ "name": "one", "size": 4, "signed": true },
{ "name": "two", "size": 4, "signed": true },
{ "name": "three", "size": 4, "signed": true }
];
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
value: { "one": -1, "two": -1, "three": -8 },
size: 2
});
});
it('Reads an unsigned 12 bit number', function() {
var buf = new Buffer([0xff, 0x80]);
var typeArgs = [
{ "name": "one", "size": 12, "signed": false }
];
assert.deepEqual(getReader(utils.bitfield)(buf, 0, typeArgs, {}), {
value: { "one": 4088 },
size: 2
});
});
it('Reads a complex structure', function() {
var buf = new Buffer([0x00, 0x00, 0x03, 0x05, 0x30, 0x42, 0xE0, 0x65]);
var typeArgs = [
{ "name": "x", "size": 26, "signed": true },
{ "name": "y", "size": 12, "signed": true },
{ "name": "z", "size": 26, "signed": true }
];
var value = { x: 12, y: 332, z: 4382821 };
assert.deepEqual(getReader(utils.bitfield)(buf, 0, typeArgs, {}), {
value: value,
size: 8
});
});
it('Writes an unsigned 8 bit number', function() {
var buf = new Buffer(1);
var typeArgs = [
{ "name": "one", "size": 8, "signed": false }
];
var value = { "one": 0xff };
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 1);
assert.deepEqual(buf, new Buffer([0xff]));
});
it('Writes a signed 8 bit number', function() {
var buf = new Buffer(1);
var typeArgs = [
{ "name": "one", "size": 8, "signed": true }
];
var value = { "one": -1 };
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 1);
assert.deepEqual(buf, new Buffer([0xff]));
});
it('Writes multiple signed 8 bit numbers', function() {
var buf = new Buffer(3);
var typeArgs = [
{ "name": "one", "size": 8, "signed": true },
{ "name": "two", "size": 8, "signed": true },
{ "name": "three", "size": 8, "signed": true }
];
var value = { "one": -1, "two": -128, "three": 18 };
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 3);
assert.deepEqual(buf, new Buffer([0xff, 0x80, 0x12]));
});
it('Writes multiple unsigned 4 bit numbers', function() {
var buf = new Buffer(2);
var typeArgs = [
{ "name": "one", "size": 4, "signed": false },
{ "name": "two", "size": 4, "signed": false },
{ "name": "three", "size": 4, "signed": false }
];
var value = { "one": 15, "two": 15, "three": 8 };
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 2);
assert.deepEqual(buf, new Buffer([0xff, 0x80]));
});
it('Writes multiple signed 4 bit numbers', function() {
var buf = new Buffer(2);
var typeArgs = [
{ "name": "one", "size": 4, "signed": true },
{ "name": "two", "size": 4, "signed": true },
{ "name": "three", "size": 4, "signed": true }
];
var value = { "one": -1, "two": -1, "three": -8 };
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 2);
assert.deepEqual(buf, new Buffer([0xff, 0x80]));
});
it('Writes an unsigned 12 bit number', function() {
var buf = new Buffer(2);
var typeArgs = [
{ "name": "one", "size": 12, "signed": false }
];
var value = { "one": 4088 };
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 2);
assert.deepEqual(buf, new Buffer([0xff, 0x80]));
});
it('Writes a complex structure', function() {
var buf = new Buffer(8);
var typeArgs = [
{ "name": "x", "size": 26, "signed": true },
{ "name": "y", "size": 12, "signed": true },
{ "name": "z", "size": 26, "signed": true }
];
var value = { x: 12, y: 332, z: 4382821 };
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 8);
assert.deepEqual(buf, new Buffer([0x00, 0x00, 0x03, 0x05, 0x30, 0x42, 0xE0, 0x65]));
});
});
});