diff --git a/packages/openapi-sampler/src/samplers/StringSampler.ts b/packages/openapi-sampler/src/samplers/StringSampler.ts index 8528b723..792ed981 100644 --- a/packages/openapi-sampler/src/samplers/StringSampler.ts +++ b/packages/openapi-sampler/src/samplers/StringSampler.ts @@ -55,30 +55,61 @@ export class StringSampler implements Sampler { const randExp = new RandExp(pattern); if (min) { - // ADHOC: make a probe for regex using min quantifier value - // e.g. ^[a]+[b]+$ expect 'ab', ^[a-z]*$ expect '' + return this.sampleMinLength(randExp, min, max); + } + + randExp.max = max ?? randExp.max; + randExp.randInt = (a, b) => Math.floor((a + b) / 2); + + const result = randExp.gen(); + + return !!max && result.length > max && this.hasInfiniteQuantifier(pattern) + ? this.sampleInfiniteQuantifier(randExp, max) + : result; + } + + private hasInfiniteQuantifier(pattern: string | RegExp) { + const pat = pattern.toString(); + + return ['+', '*', ',}'].some((q) => pat.includes(q)); + } - randExp.max = 0; - randExp.randInt = (a, _) => a; + private sampleInfiniteQuantifier(randExp: RandExp, max: number): string { + + randExp.randInt = (a, b) => Math.floor((a + b) / 2); + + for (let i = 1, lmax = max; lmax > 0; lmax = Math.floor(max / ++i)) { + randExp.max = lmax; const result = randExp.gen(); - if (result.length >= min) { + if (result.length <= max) { return result; } + } - // ADHOC: fallback for failed min quantifier probe with doubled min length + return ''; + } - randExp.max = 2 * min; - randExp.randInt = (a, b) => Math.floor((a + b) / 2); + private sampleMinLength(randExp: RandExp, min: number, max: number) { + // ADHOC: make a probe for regex using min quantifier value + // e.g. ^[a]+[b]+$ expect 'ab', ^[a-z]*$ expect '' - return this.adjustMaxLength(randExp.gen(), max); + randExp.max = 0; + randExp.randInt = (a, _) => a; + + const result = randExp.gen(); + + if (result.length >= min) { + return result; } - randExp.max = max ?? randExp.max; + // ADHOC: fallback for failed min quantifier probe with doubled min length + + randExp.max = 2 * min; randExp.randInt = (a, b) => Math.floor((a + b) / 2); - return randExp.gen(); + return this.adjustMaxLength(randExp.gen(), max); } private checkLength( diff --git a/packages/openapi-sampler/tests/string.spec.ts b/packages/openapi-sampler/tests/string.spec.ts index 12d937ac..7880a90d 100644 --- a/packages/openapi-sampler/tests/string.spec.ts +++ b/packages/openapi-sampler/tests/string.spec.ts @@ -1,7 +1,18 @@ import { sample } from '../src'; + describe('StringSampler', () => { [ + { + input: { + maxLength: 55, + minLength: 0, + format: 'pattern', + pattern: '^[A-Za-z0-9._%-]+@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{1,4}$', + type: 'string' + }, + expected: "gggggg@FFFFFF.FFFFFF.FFFFFF.FFFFFF.FFFFFF.FFFFFF.zz" + }, { input: { type: 'string',