diff --git a/packages/openapi-sampler/src/samplers/StringSampler.ts b/packages/openapi-sampler/src/samplers/StringSampler.ts index 678da90f..8528b723 100644 --- a/packages/openapi-sampler/src/samplers/StringSampler.ts +++ b/packages/openapi-sampler/src/samplers/StringSampler.ts @@ -30,10 +30,10 @@ export class StringSampler implements Sampler { 'relative-json-pointer': () => '1/relative/json/pointer', 'regex': () => '/regex/', 'pattern': ( - _min: number, + min: number, max: number, { pattern }: { pattern: string | RegExp } - ) => this.patternSample(pattern, max), + ) => this.patternSample(pattern, min, max), 'default': (min: number, max: number) => this.adjustLength('lorem', min, max) }; @@ -47,9 +47,34 @@ export class StringSampler implements Sampler { return this.checkLength(sampler(min || 0, max, schema), format, min, max); } - private patternSample(pattern: string | RegExp, max?: number): string { + private patternSample( + pattern: string | RegExp, + min?: number, + max?: number + ): string { 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 '' + + randExp.max = 0; + randExp.randInt = (a, _) => a; + + const result = randExp.gen(); + + if (result.length >= min) { + return result; + } + + // 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 this.adjustMaxLength(randExp.gen(), max); + } + randExp.max = max ?? randExp.max; randExp.randInt = (a, b) => Math.floor((a + b) / 2); @@ -95,4 +120,8 @@ export class StringSampler implements Sampler { Math.min(Math.max(sample.length, minLength), maxLength) ); } + + private adjustMaxLength(sample: string, max?: number): string { + return max && sample.length >= max ? sample.substring(0, max) : sample; + } } diff --git a/packages/openapi-sampler/tests/string.spec.ts b/packages/openapi-sampler/tests/string.spec.ts index c5bc24b5..12d937ac 100644 --- a/packages/openapi-sampler/tests/string.spec.ts +++ b/packages/openapi-sampler/tests/string.spec.ts @@ -60,6 +60,73 @@ describe('StringSampler', () => { }, expected: 'EEEEE44444' }, + { + input: { + type: 'string', + format: 'pattern', + maxLength: 4, + minLength: 4, + pattern: '^[0-9]+$' + }, + expected: '4444' + }, + { + input: { + type: 'string', + format: 'pattern', + minLength: 5, + maxLength: 6, + pattern: '^[0-9]+$' + }, + expected: '444444' + }, + { + input: { + type: 'string', + format: 'pattern', + minLength: 5, + maxLength: 100, + pattern: '^[0-9]+$' + }, + expected: '444444' + }, + { + input: { + type: 'string', + format: 'pattern', + minLength: 4, + pattern: '^[0-9]+$' + }, + expected: '44444' + }, + { + input: { + type: 'string', + format: 'pattern', + minLength: 4, + pattern: '^[0-9]{4,5}$' + }, + expected: '0000' + }, + { + input: { + type: 'string', + format: 'pattern', + minLength: 5, + pattern: '^[0-9]{3,5}[A-Z]{3}$' + }, + expected: '000AAA' + }, + { + input: { + type: 'string', + format: 'pattern', + maxLength: 4, + minLength: 4, + pattern: "[^<>%=']*$" + }, + expected: 'QQQQ' + }, { input: { type: 'string', @@ -69,6 +136,26 @@ describe('StringSampler', () => { }, expected: '' }, + { + input: { + type: 'string', + format: 'pattern', + pattern: '^[a]+[b]+$', + maxLength: 2, + minLength: 2 + }, + expected: 'ab' + }, + { + input: { + type: 'string', + format: 'pattern', + pattern: '^[a]{2,4}[b]{2,4}$', + maxLength: 4, + minLength: 4 + }, + expected: 'aabb' + }, { input: { type: 'string', @@ -266,6 +353,26 @@ describe('StringSampler', () => { expected: 'Sample string cannot be generated by boundaries: maxLength=5, format=pattern' }, + { + input: { + minLength: 5, + pattern: '^[0-9]{3}', + type: 'string' + }, + expected: + 'Sample string cannot be generated by boundaries: minLength=5, format=pattern' + }, + { + input: { + type: 'string', + format: 'pattern', + pattern: '^[a]+[b]+$', + maxLength: 1, + minLength: 1 + }, + expected: + 'Sample string cannot be generated by boundaries: minLength=1, maxLength=1, format=pattern' + }, { input: { type: 'string',