UNPKG

ipld-garbage

Version:

Garbage data generator for the IPLD Data Model

188 lines 3.72 kB
import { CID } from 'multiformats/cid'; import { create as createDigest } from 'multiformats/hashes/digest'; const kinds = [ 'list', 'map', 'string', 'bytes', 'boolean', 'integer', 'float', 'null', 'CID' ]; const codecs = [ 85, 112, 113, 297 ]; const hashes = [ [ 18, 256 ], [ 22, 256 ], [ 27, 256 ], [ 45600, 256 ], [ 19, 512 ], [ 21, 384 ], [ 20, 512 ] ]; const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()-_=+[]{}|\\:;\'",.<>?/ \t\n\u263A'; const baseOptions = { initialWeights: { map: 10, list: 10 } }; export function garbage(count = 200, options) { options = Object.assign({}, baseOptions, options); return generate(count, options)[1]; } function generate(count, options) { let totWeight = 0; const weights = Object.assign({}, options.initialWeights, options.weights || {}); if (options.initialWeights) { options = Object.assign(options, { initialWeights: null }); } const types = kinds.map(t => { const weight = weights && typeof weights[t] === 'number' ? weights[t] : 1; if (weight < 0) { throw new TypeError('Cannot have a negative weight'); } totWeight += weight; return [ t, weight ]; }); if (totWeight === 0) { throw new Error('Cannot have a total weight of zero'); } const rnd = Math.random() * totWeight; let wacc = 0; for (const [type, weight] of types) { wacc += weight; if (wacc >= rnd) { return generators[type](count, options); } } throw new Error('Internal error'); } function rndSize(bias = 5) { return Math.abs(Math.floor(5 / (1 - Math.random() ** 2) - 5 + Math.random() * bias)); } function rndChar() { return charset.charAt(Math.floor(Math.random() * charset.length)); } function rndByte() { return Math.floor(Math.random() * 256); } const generators = { list(count, options) { const res = []; const len = rndSize(); let size = 0; for (let i = 0; i < len && size < count; i++) { const x = generate(count - size, options); res.push(x[1]); size += x[0]; } return [ size, res ]; }, map(count, options) { const res = {}; const len = rndSize(); let size = 0; for (let i = 0; i < len && size < count; i++) { const key = generators.string(5)[1]; const x = generate(count - size, options); res[key] = x[1]; size += x[0] + key.length; } return [ size, res ]; }, string(bias = 50) { const len = rndSize(bias); const res = []; for (let i = 0; i < len; i++) { res.push(rndChar()); } return [ len, res.join('') ]; }, bytes(bias = 50) { const len = rndSize(bias); const res = new Uint8Array(len); for (let i = 0; i < len; i++) { res[i] = rndByte(); } return [ len, res ]; }, boolean() { return [ 1, Math.random() > 0.5 ]; }, integer() { return [ 1, Math.floor(Number.MAX_SAFE_INTEGER * Math.random()) * (Math.random() < 0.5 ? -1 : 1) ]; }, float() { return [ 1, Math.tan((Math.random() - 0.5) * Math.PI) ]; }, null() { return [ 1, null ]; }, CID() { const hasher = hashes[Math.floor(Math.random() * hashes.length)]; const codec = codecs[Math.floor(Math.random() * codecs.length)]; const bytes = new Uint8Array(hasher[1] / 8); for (let i = 0; i < bytes.length; i++) { bytes[i] = rndByte(); } return [ bytes.length, CID.create(1, codec, createDigest(hasher[0], bytes)) ]; } };