diff --git a/src/chunker/rabin.js b/src/chunker/rabin.js index 7d76a44..cb4a84b 100644 --- a/src/chunker/rabin.js +++ b/src/chunker/rabin.js @@ -2,6 +2,7 @@ const BufferList = require('bl') const { create } = require('rabin-wasm') +const errcode = require('err-code') module.exports = async function * rabinChunker (source, options) { const rabin = jsRabin() @@ -12,12 +13,27 @@ module.exports = async function * rabinChunker (source, options) { avg = options.avgChunkSize min = options.minChunkSize max = options.maxChunkSize + } else if (!options.avgChunkSize) { + throw errcode(new Error('please specify an average chunk size'), 'ERR_INVALID_AVG_CHUNK_SIZE') } else { avg = options.avgChunkSize min = avg / 3 max = avg + (avg / 2) } + // validate min/max/avg in the same way as go + if (min < 16) { + throw errcode(new Error('rabin min must be greater than 16'), 'ERR_INVALID_MIN_CHUNK_SIZE') + } + + if (max < min) { + max = min + } + + if (avg < min) { + avg = min + } + const sizepow = Math.floor(Math.log2(avg)) for await (const chunk of rabin(source, { diff --git a/test/chunker-rabin.spec.js b/test/chunker-rabin.spec.js index 4ac92bf..4b31b54 100644 --- a/test/chunker-rabin.spec.js +++ b/test/chunker-rabin.spec.js @@ -56,7 +56,7 @@ describe('chunker: rabin', function () { const chunks = await all(chunker([b1], { ...defaultOptions, maxChunkSize: 262144, - minChunkSize: 1, + minChunkSize: 18, avgChunkSize: 256 })) @@ -83,4 +83,53 @@ describe('chunker: rabin', function () { expect(chunk).to.have.length.lte(opts.maxChunkSize) }) }) + + it('throws when min chunk size is too small', async () => { + const opts = { + ...defaultOptions, + minChunkSize: 1, + maxChunkSize: 100 + } + + try { + await all(chunker([], opts)) + throw new Error('Should have thrown') + } catch (err) { + expect(err.code).to.equal('ERR_INVALID_MIN_CHUNK_SIZE') + } + }) + + it('throws when avg chunk size is not specified', async () => { + const opts = { + ...defaultOptions, + avgChunkSize: undefined + } + + try { + await all(chunker([], opts)) + throw new Error('Should have thrown') + } catch (err) { + expect(err.code).to.equal('ERR_INVALID_AVG_CHUNK_SIZE') + } + }) + + it('uses the min chunk size when max and avg are too small', async () => { + let file = Buffer.concat([rawFile, Buffer.from('hello')]) + const opts = { + ...defaultOptions, + minChunkSize: 100, + maxChunkSize: 5, + avgChunkSize: 5 + } + + const chunks = await all(chunker([file], opts)) + + chunks.forEach((chunk, index) => { + if (index === chunks.length - 1) { + expect(chunk.length).to.equal(81) + } else { + expect(chunk.length).to.equal(100) + } + }) + }) })