dnssd
Version:
Bonjour/Avahi-like service discovery in pure JavaScript
408 lines (311 loc) • 13.1 kB
JavaScript
const chai = require('chai');
const expect = chai.expect;
const rewire = require('rewire');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
chai.use(sinonChai);
const dir = process['test-dir'] || '../../src';
const BufferWrapper = rewire(dir + '/BufferWrapper');
describe('BufferWrapper', function() {
describe('Buffer read/write aliases', function() {
it('#readUInt8(): should return value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0x01]));
expect(wrapper.readUInt8()).to.equal(0x01);
expect(wrapper.tell()).to.equal(1);
});
it('#readUInt16BE(): should return value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0x01,0x02]));
expect(wrapper.readUInt16BE()).to.equal(0x0102);
expect(wrapper.tell()).to.equal(2);
});
it('#readUInt32BE(): should return value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.readUInt32BE()).to.equal(0x01020304);
expect(wrapper.tell()).to.equal(4);
});
it('#readUIntBE(): should return value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.readUIntBE(4)).to.equal(0x01020304);
expect(wrapper.tell()).to.equal(4);
});
it('#writeUInt8(): should write value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0]));
wrapper.writeUInt8(0x04);
expect(wrapper.buffer).to.eql(new Buffer([0x04]));
expect(wrapper.tell()).to.equal(1);
});
it('#writeUInt16BE(): should write value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0,0]));
wrapper.writeUInt16BE(0x0405);
expect(wrapper.buffer).to.eql(new Buffer([0x04,0x05]));
expect(wrapper.tell()).to.equal(2);
});
it('#writeUInt32BE(): should write value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0,0,0,0]));
wrapper.writeUInt32BE(0x01020304);
expect(wrapper.buffer).to.eql(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.tell()).to.equal(4);
});
it('#writeUIntBE(): should write value and increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0,0,0,0]));
wrapper.writeUIntBE(0x01020304, 4);
expect(wrapper.buffer).to.eql(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.tell()).to.equal(4);
});
});
describe('Other read/writes', function() {
it('#readString(): should read utf8 string, increment position', function() {
const str = 'generic string';
const wrapper = new BufferWrapper(new Buffer(str));
expect(wrapper.readString(str.length)).to.equal(str);
expect(wrapper.tell()).to.equal(str.length);
});
it('#writeString(): should write utf8 string, increment position', function() {
const str = 'generic string';
const wrapper = new BufferWrapper(new Buffer(str.length));
wrapper.writeString(str);
expect(wrapper.buffer).to.eql(new Buffer(str));
expect(wrapper.tell()).to.equal(str.length);
});
it('#read(): should read n bytes, increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.read(4)).to.eql(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.tell()).to.equal(4);
});
it('#add(): should add buffer, increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0,0,0,0]));
wrapper.add(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.buffer).to.eql(new Buffer([0x01,0x02,0x03,0x04]));
expect(wrapper.tell()).to.equal(4);
});
it('#remaining(): should show number of bytes til end of buffer', function() {
const wrapper = new BufferWrapper(new Buffer([0,0,0,0]));
expect(wrapper.remaining()).to.equal(4);
});
it('#skip(): should skip n bytes, increment position', function() {
const wrapper = new BufferWrapper(new Buffer([0,0,0,0]));
wrapper.skip(2);
expect(wrapper.tell()).to.equal(2);
});
it('#trim(): should trim/return internal buffer up to position', function() {
const wrapper = new BufferWrapper(new Buffer([0x01,0x02,0x03,0x04]));
wrapper.skip(2);
expect(wrapper.unwrap()).to.eql(new Buffer([0x01,0x02]));
});
});
describe('#_checkLength()', function() {
const wrapper = new BufferWrapper(new Buffer([0,0,0,0]));
sinon.stub(wrapper, '_grow');
beforeEach(function() {
wrapper._grow.reset();
});
it('should not grow if not needed', function() {
wrapper._checkLength(4);
expect(wrapper._grow).to.not.have.been.called;
});
it('should grow with a default of 512', function() {
wrapper._checkLength(8);
expect(wrapper._grow).to.have.been.calledWith(512);
});
it('should grow by 1.5 * needed if > 512', function() {
wrapper._checkLength(604);
expect(wrapper._grow).to.have.been.calledWith(900);
});
});
describe('#_grow()', function() {
it('should add n sized buffer to end', function() {
const wrapper = new BufferWrapper(new Buffer(0));
wrapper._grow(5);
expect(wrapper.buffer.length).to.equal(5);
});
});
describe('#indexOf()', function() {
describe('should use Buffer.indexOf in newer versions of node', function() {
it('should find index', function() {
const wrapper = new BufferWrapper();
wrapper.add(new Buffer([0,1,2,3,4]));
expect(wrapper.indexOf(new Buffer([2,3]))).to.equal(2);
});
it('should return -1 if not found', function() {
const wrapper = new BufferWrapper();
wrapper.add(new Buffer([0,1,2,3,4]));
expect(wrapper.indexOf(new Buffer([5,6]))).to.equal(-1);
});
});
describe('should do naive search in older versions of node', function() {
class OldBuffer extends Buffer {}
OldBuffer.prototype.indexOf = null; // older versions don't have indexOf
let revert;
before(function() {
revert = BufferWrapper.__set__('Buffer', OldBuffer);
});
after(function() {
revert();
});
it('should find index', function() {
const wrapper = new BufferWrapper();
wrapper.add(new Buffer([0,1,2,3,4]));
expect(wrapper.indexOf(new Buffer([2,3]))).to.equal(2);
});
it('should return -1 if not found', function() {
const wrapper = new BufferWrapper();
wrapper.add(new Buffer([0,1,2,3,4]));
expect(wrapper.indexOf(new Buffer([5,6]))).to.equal(-1);
});
});
});
describe('#readFQDN()', function() {
it('should read basic names without pointers', function() {
const wrapper = new BufferWrapper();
wrapper.writeUInt8(3); // 'www'.length
wrapper.writeString('www');
wrapper.writeUInt8(6); // 'google'.length
wrapper.writeString('google');
wrapper.writeUInt8(3); // 'com'.length
wrapper.writeString('com');
wrapper.writeUInt8(0); // terminating root label: .
const finalPos = wrapper.tell();
wrapper.seek(0);
expect(wrapper.readFQDN()).to.equal('www.google.com.');
expect(wrapper.tell()).to.equal(finalPos);
});
it('should follow pointers to read names', function() {
const wrapper = new BufferWrapper();
wrapper.writeUInt8(3);
wrapper.writeString('www');
wrapper.writeUInt8(6);
wrapper.writeString('google');
wrapper.writeUInt8(3);
wrapper.writeString('com');
wrapper.writeUInt8(0);
const readPos = wrapper.tell();
wrapper.writeUInt16BE(0xC000 + 0); // points to beginning
const finalPos = wrapper.tell();
wrapper.seek(readPos);
expect(wrapper.readFQDN()).to.equal('www.google.com.');
expect(wrapper.tell()).to.equal(finalPos);
});
it('should follow partial pointers to read names', function() {
const wrapper = new BufferWrapper();
wrapper.writeUInt8(6);
wrapper.writeString('google');
wrapper.writeUInt8(3);
wrapper.writeString('com');
wrapper.writeUInt8(0);
const readPos = wrapper.tell();
wrapper.writeUInt8(3);
wrapper.writeString('www');
wrapper.writeUInt16BE(0xC000 + 0); // points to beginning
const finalPos = wrapper.tell();
wrapper.seek(readPos);
expect(wrapper.readFQDN()).to.equal('www.google.com.');
expect(wrapper.tell()).to.equal(finalPos);
});
it('should follow multiple pointers to read names', function() {
const wrapper = new BufferWrapper();
wrapper.writeUInt8(3);
wrapper.writeString('com');
wrapper.writeUInt8(0);
wrapper.writeUInt8(6);
wrapper.writeString('google');
wrapper.writeUInt16BE(0xC000 + 0); // points to beginning
const readPos = wrapper.tell();
wrapper.writeUInt8(3);
wrapper.writeString('www');
wrapper.writeUInt16BE(0xC000 + 5); // points to right before "google" length
const finalPos = wrapper.tell();
wrapper.seek(readPos);
expect(wrapper.readFQDN()).to.equal('www.google.com.');
expect(wrapper.tell()).to.equal(finalPos);
});
});
describe('#writeFQDN()', function() {
it('should do basic name writes w/o compression pointers', function() {
const wrapper = new BufferWrapper();
wrapper.writeFQDN('www.google.com.');
const expected = new BufferWrapper();
expected.writeUInt8(3);
expected.writeString('www');
expected.writeUInt8(6);
expected.writeString('google');
expected.writeUInt8(3);
expected.writeString('com');
expected.writeUInt8(0);
expect(wrapper.unwrap().equals(expected.unwrap())).to.be.true;
});
it('should do whole compression pointers', function() {
const wrapper = new BufferWrapper();
wrapper.writeUInt8(3);
wrapper.writeString('www');
wrapper.writeUInt8(6);
wrapper.writeString('google');
wrapper.writeUInt8(3);
wrapper.writeString('com');
wrapper.writeUInt8(0);
const expected = new BufferWrapper();
expected.writeUInt8(3);
expected.writeString('www');
expected.writeUInt8(6);
expected.writeString('google');
expected.writeUInt8(3);
expected.writeString('com');
expected.writeUInt8(0);
expected.writeUInt16BE(0xC000 + 0); // points to beginning
wrapper.writeFQDN('www.google.com.');
expect(wrapper.unwrap().equals(expected.unwrap())).to.be.true;
});
it('should do partial compression pointers', function() {
const wrapper = new BufferWrapper();
wrapper.writeUInt8(6);
wrapper.writeString('google');
wrapper.writeUInt8(3);
wrapper.writeString('com');
wrapper.writeUInt8(0);
wrapper.writeUInt8(3);
wrapper.writeString('www');
wrapper.writeUInt16BE(0xC000 + 0); // points to beginning
const expected = new BufferWrapper();
expected.writeUInt8(6);
expected.writeString('google');
expected.writeUInt8(3);
expected.writeString('com');
expected.writeUInt8(0);
expected.writeUInt8(3);
expected.writeString('www');
expected.writeUInt16BE(0xC000 + 0);
expected.writeUInt16BE(0xC000 + 12); // points to right beore "www" length
wrapper.writeFQDN('www.google.com.');
expect(wrapper.unwrap().equals(expected.unwrap())).to.be.true;
});
it('should not try to compress pointers themselves again', function() {
const wrapper = new BufferWrapper();
// this could be another pointer, or other not needed data. it should be
// ignored and the later pointer, "0xC000 + 2", should not be replaced with
// "0xC000 + 0" just becuase it found "0xC000 + 2" here.
wrapper.writeUInt16BE(0xC000 + 2);
wrapper.writeUInt8(3);
wrapper.writeString('com');
wrapper.writeUInt8(0);
wrapper.writeUInt8(6);
wrapper.writeString('google');
wrapper.writeUInt16BE(0xC000 + 2); // points to beginning
wrapper.writeUInt8(3);
wrapper.writeString('www');
wrapper.writeUInt16BE(0xC000 + 7); // points to right before "google" length
const expected = new BufferWrapper();
expected.writeUInt16BE(0xC000 + 2);
expected.writeUInt8(3);
expected.writeString('com');
expected.writeUInt8(0);
expected.writeUInt8(6);
expected.writeString('google');
expected.writeUInt16BE(0xC000 + 2);
expected.writeUInt8(3);
expected.writeString('www');
expected.writeUInt16BE(0xC000 + 7);
expected.writeUInt16BE(0xC000 + 16); // points to right beore "www" length
wrapper.writeFQDN('www.google.com.');
expect(wrapper.unwrap().equals(expected.unwrap())).to.be.true;
});
});
});