fuzz.ts
1 import fs from "fs"; 2 import path from "path"; 3 4 import { ReadableStreamSearch } from "../src"; 5 import { BAD_INPUT_DIR, cmp, makeStream } from "./util"; 6 7 function randomString(min: number, max: number): string { 8 return Array.from( 9 { length: min + Math.floor(Math.random() * (max - min)) }, 10 () => String.fromCharCode(Math.floor(Math.random() * 256)), 11 ).join(""); 12 } 13 14 function randomlySplit(input: string): string[] { 15 const cuts = [ 16 ...new Set( 17 Array.from({ length: Math.floor(Math.random() * input.length) }, () => 18 Math.floor(Math.random() * input.length), 19 ).filter((n) => n > 0), 20 ), 21 ].sort((a, b) => a - b); 22 23 if (!cuts.length) { 24 return [input]; 25 } 26 27 const output: string[] = [input.slice(0, cuts[0])]; 28 for (let i = 0; i < cuts.length - 1; i++) { 29 const a = cuts[i]; 30 const b = cuts[i + 1]; 31 32 output.push(input.slice(a, b)); 33 } 34 35 output.push(input.slice(cuts[cuts.length - 1])); 36 37 return output; 38 } 39 40 function randomlySplice(haystack: string, needle: string): string { 41 const split = randomlySplit(haystack); 42 return Array.from({ length: split.length * 2 - 1 }, (_, i) => 43 i % 2 === 0 ? split[i / 2] : needle, 44 ).join(""); 45 } 46 47 (async () => { 48 while (true) { 49 const needle = randomString(1, 1 << 8); 50 const haystack = randomlySplice(randomString(0, 1 << 8), needle); 51 const chunks = randomlySplit(haystack); 52 const expected = haystack.split(needle); 53 54 const search = new ReadableStreamSearch(needle, makeStream(chunks)); 55 const result = await search.allStrings(); 56 57 if ( 58 result.length !== expected.length || 59 result.some((v, i) => !cmp(v, expected[i])) 60 ) { 61 fs.mkdirSync(BAD_INPUT_DIR, { recursive: true }); 62 fs.writeFileSync( 63 path.join(BAD_INPUT_DIR, `${Date.now()}.json`), 64 JSON.stringify({ needle, chunks }), 65 ); 66 process.stdout.write("!"); 67 } else { 68 process.stdout.write("."); 69 } 70 } 71 })().catch(console.error);