Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[test/lib] refactor fsm to be a line shorter, and handle byte consump…

…tion internally
  • Loading branch information...
commit 7271503f16ba0431690819f2003b4171433417be 1 parent 741cbe5
@tmpvar tmpvar authored
Showing with 157 additions and 115 deletions.
  1. +49 −35 lib/fsm.js
  2. +60 −80 lib/pack/index.js
  3. +48 −0 test/tests/fsm-test.js
View
84 lib/fsm.js
@@ -1,3 +1,25 @@
+
+
+var join = function(a, b) {
+ if (!a) {
+ return b;
+ } else if (!b) {
+ return a;
+ } else if (Buffer.isBuffer(a)) {
+ return Buffer.concat([a,b], a.length + b.length);
+ } else {
+ return a+b;
+ }
+};
+
+var slice = function(b, start, end) {
+ if (Buffer.isBuffer(b)) {
+ return b.slice(start, end);
+ } else {
+ return b.substring(start, end);
+ }
+};
+
module.exports = function(states, callback) {
var state = Object.keys(states)[0];
@@ -6,59 +28,51 @@ module.exports = function(states, callback) {
var initialState = state;
var consumed = states[state].call(ret, data);
- if (data && consumed < data.length) {
- if (data.slice) {
- ret(data.slice(consumed));
- } else if (data.substring) {
- ret(data.substring(consumed))
- } else {
- console.log('WARNING: not sure how to slice', typeof data);
- }
+ if (data && consumed && consumed < data.length) {
+ ret(slice(data, consumed));
}
};
ret.change = function(newState) {
state = newState;
- states[newState].callCount = 0;
};
ret.done = function() {
callback && callback.apply(this, arguments);
};
+ if (state === 'init') {
+ ret();
+ }
+
+ return ret;
+};
+
+
+module.exports.want = function(count, fn) {
+
+ fn.callCount = 0;
var cache = null;
- ret.want = function(bytes, data, fn) {
- var incomingLength = data.length;
- var cacheLength = (cache) ? cache.length : 0;
- var originalState = state;
+ return function(data) {
+
if (cache) {
- if (Buffer.isBuffer(data)) {
- data = Buffer.concat([cache, data], data.length + cache.length);
- } else {
- data = cache + data;
- }
+ data = join(cache, data);
cache = null;
}
- if (data.length >= bytes) {
- if (Buffer.isBuffer(data)) {
- fn.call(this, data.slice(0, bytes), states[state].callCount);
- states[originalState].callCount++;
- return bytes;
- } else {
- fn.call(this, data.substring(0, bytes), states[state].callCount);
- states[originalState].callCount++;
- return bytes;
+ if (data.length >= count) {
+
+ var ret = fn.call(this, slice(data, 0, count), fn.callCount);
+ fn.callCount++;
+ if (typeof ret === 'undefined') {
+ return count;
}
+ return ret;
+
} else {
- cache = data;
- return incomingLength;
+ cache = join(cache, data);
+ return 0;
}
};
+};
- if (state === 'init') {
- ret();
- }
-
- return ret;
-};
View
140 lib/pack/index.js
@@ -16,91 +16,71 @@ module.exports.createParserStream = function() {
};
var parser = fsm({
- ident : function(data) {
- return this.want(4, data, function(buffer) {
- obj.ident = buffer;
- this.change('version')
- });
- },
- version : function(data) {
- return this.want(4, data, function(buffer) {
- obj.version = buffer.readUInt32BE(0);
- if (obj.version === 2) {
- this.change('first level fanout');
- } else {
- throw new Error('fanout version 1.0 not implemented');
- }
+ 'ident' : fsm.want(4, function(buffer) {
+ obj.ident = buffer;
+ this.change('version')
+ }),
- });
- },
-
- 'first level fanout' : function(data) {
- return this.want(4, data, function(buffer) {
- obj.fanout.push(buffer.readUInt32BE(0));
- if (obj.fanout.length === 256) {
- obj.total = obj.fanout[obj.fanout.length-1];
- this.change('entries')
- }
- });
- },
+ 'version' : fsm.want(4, function(buffer) {
+ obj.version = buffer.readUInt32BE(0);
+ this.change('first level fanout');
+ }),
- entries : function(data) {
- return this.want(20, data, function(buffer) {
- obj.entries.push({
- sha : buffer.toString('hex')
- });
+ 'first level fanout' : fsm.want(4, function(buffer) {
+ obj.fanout.push(buffer.readUInt32BE(0));
- if (obj.entries.length >= obj.total) {
- this.change('crc32')
- }
- });
- },
-
- crc32 : function(data) {
- return this.want(4, data, function(buffer, i) {
- obj.entries[i].crc32 = buffer.toString('hex');
- if (i >= obj.entries.length - 1) {
- this.change('small offset');
- }
- });
- },
-
- 'small offset' : function(data) {
- return this.want(4, data, function(buffer, i) {
- obj.entries[i].offset = buffer.readUInt32BE(0);
- if (i >= obj.entries.length - 1) {
- // TODO: >4gb packfiles
- // basically this means the offsets that we collected
- // are indexes into another larger table
- //this.change('pack offset');
- this.change('packfile checksum');
- }
- });
- },
-
- 'pack offset' : function(data) {
- return this.want(8, data, function(buffer, i) {
- obj.entries[i].largeOffset = buffer.readDoubleBE(0);
- if (i >= obj.entries.length - 1) {
- this.change('packfile checksum');
- }
+ if (obj.fanout.length === 256) {
+ obj.total = obj.fanout[obj.fanout.length-1];
+ this.change('entries')
+ }
+ }),
+
+ 'entries' : fsm.want(20, function(buffer) {
+ obj.entries.push({
+ sha : buffer.toString('hex')
});
- },
-
- 'packfile checksum' : function(data) {
- return this.want(20, data, function(buffer) {
- obj.packfileChecksum = buffer.toString('hex');
- this.change('indexfile checksum');
- })
- },
-
- 'indexfile checksum' : function(data) {
- return this.want(20, data, function(buffer) {
- obj.indexfileChecksum = buffer.toString('hex');
- this.done(obj);
- })
- }
+
+ if (obj.entries.length >= obj.total) {
+ this.change('crc32')
+ }
+ }),
+
+ 'crc32' : fsm.want(4, function(buffer, i) {
+ obj.entries[i].crc32 = buffer.toString('hex');
+ if (i >= obj.entries.length - 1) {
+ this.change('small offset');
+ }
+ }),
+
+ 'small offset' : fsm.want(4, function(buffer, i) {
+ obj.entries[i].offset = buffer.readUInt32BE(0);
+ if (i >= obj.entries.length - 1) {
+ // TODO: >4gb packfiles
+ // basically this means the offsets that we collected
+ // are indexes into another larger table
+ //this.change('pack offset');
+ this.change('packfile checksum');
+ }
+ }),
+
+ 'pack offset' : fsm.want(8, function(buffer, i) {
+ obj.entries[i].largeOffset = buffer.readDoubleBE(0);
+ if (i >= obj.entries.length - 1) {
+ this.change('packfile checksum');
+ }
+ }),
+
+ 'packfile checksum' : fsm.want(20, function(buffer) {
+ obj.packfileChecksum = buffer.toString('hex');
+ this.change('indexfile checksum');
+ }),
+
+ 'indexfile checksum' : fsm.want(20, function(buffer) {
+ obj.indexfileChecksum = buffer.toString('hex');
+ this.done(obj);
+ })
+
}, function(obj) {
s.end(obj);
});
View
48 test/tests/fsm-test.js
@@ -0,0 +1,48 @@
+var test = require('tap').test,
+ fsm = require('../../lib/fsm');
+
+module.exports = {
+ "fsm: test want (string)" : function(t) {
+ var count = 0;
+ var res = '';
+ var fn = fsm.want(4, function(data) {
+ console.log(arguments);
+ count++;
+ res+=data;
+ });
+
+ t.equal(fn('1'), 0);
+ t.equal(fn('2'), 0);
+ t.equal(fn('3'), 0);
+ t.equal(fn('4'), 4); // consumed 4 bytes
+
+ t.equal(count, 1);
+ t.equal(res, '1234');
+ t.end();
+ },
+
+ "fsm: test want (string)" : function(t) {
+ var count = 0;
+ var res;
+ var fn = fsm.want(4, function(data) {
+ console.log(arguments);
+ count++;
+ res = data;
+ });
+
+ t.equal(fn(new Buffer([1])), 0);
+ t.equal(fn(new Buffer([2])), 0);
+ t.equal(fn(new Buffer([3])), 0);
+ t.equal(fn(new Buffer([4])), 4); // consumed 4 bytes
+
+ t.equal(count, 1);
+
+ t.equal(res[0], 1);
+ t.equal(res[1], 2);
+ t.equal(res[2], 3);
+ t.equal(res[3], 4);
+
+ t.end();
+ }
+
+}
Please sign in to comment.
Something went wrong with that request. Please try again.