From 7c81bd7f02067771a84a059a1f8d7fb90ec51c64 Mon Sep 17 00:00:00 2001 From: Dmitry Ostrikov Date: Mon, 25 Sep 2023 10:16:21 +0300 Subject: [PATCH 1/2] fix(sampler): introduce min-length support for string pattern format sample (#209) closes #216 --- .../src/samplers/StringSampler.ts | 20 +++++-- packages/openapi-sampler/tests/string.spec.ts | 60 +++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/packages/openapi-sampler/src/samplers/StringSampler.ts b/packages/openapi-sampler/src/samplers/StringSampler.ts index 678da90f..5eb048c5 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,11 +47,23 @@ 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); + randExp.randInt = (a, b) => Math.floor((a + b) / 2); + + if (min) { + randExp.max = 2 * min; + + const result = randExp.gen(); + + return max && result.length > max ? result.substring(0, max) : result; + } randExp.max = max ?? randExp.max; - randExp.randInt = (a, b) => Math.floor((a + b) / 2); return randExp.gen(); } diff --git a/packages/openapi-sampler/tests/string.spec.ts b/packages/openapi-sampler/tests/string.spec.ts index c5bc24b5..a0ae688d 100644 --- a/packages/openapi-sampler/tests/string.spec.ts +++ b/packages/openapi-sampler/tests/string.spec.ts @@ -60,6 +60,57 @@ describe('StringSampler', () => { }, expected: 'EEEEE44444' }, + { + input: { + maxLength: 4, + minLength: 4, + pattern: '^[0-9]+$', + type: 'string' + }, + expected: '4444' + }, + { + input: { + minLength: 5, + maxLength: 6, + pattern: '^[0-9]+$', + type: 'string' + }, + expected: '444444' + }, + { + input: { + minLength: 5, + maxLength: 100, + pattern: '^[0-9]+$', + type: 'string' + }, + expected: '444444' + }, + { + input: { + minLength: 4, + pattern: '^[0-9]+$', + type: 'string' + }, + expected: '44444' + }, + { + input: { + minLength: 4, + pattern: '^[0-9]{4,5}$', + type: 'string' + }, + expected: '4444' + }, + { + input: { + minLength: 5, + pattern: '^[0-9]{3,5}$[A-Z]{3}', + type: 'string' + }, + expected: '4444MMM' + }, { input: { type: 'string', @@ -266,6 +317,15 @@ 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', From acf4cc235393455fd285706704e0a0cecc18f1f4 Mon Sep 17 00:00:00 2001 From: Dmitry Ostrikov Date: Fri, 6 Oct 2023 13:10:18 +0300 Subject: [PATCH 2/2] fix(sampler): adjust according to code review https://github.com/NeuraLegion/har-sdk/pull/217#discussion_r1337000759 closes #216 --- .../src/samplers/StringSampler.ts | 23 +++++- packages/openapi-sampler/tests/string.spec.ts | 75 +++++++++++++++---- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/packages/openapi-sampler/src/samplers/StringSampler.ts b/packages/openapi-sampler/src/samplers/StringSampler.ts index 5eb048c5..8528b723 100644 --- a/packages/openapi-sampler/src/samplers/StringSampler.ts +++ b/packages/openapi-sampler/src/samplers/StringSampler.ts @@ -53,17 +53,30 @@ export class StringSampler implements Sampler { max?: number ): string { const randExp = new RandExp(pattern); - randExp.randInt = (a, b) => Math.floor((a + b) / 2); if (min) { - randExp.max = 2 * 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(); - return max && result.length > max ? result.substring(0, max) : result; + 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); return randExp.gen(); } @@ -107,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 a0ae688d..12d937ac 100644 --- a/packages/openapi-sampler/tests/string.spec.ts +++ b/packages/openapi-sampler/tests/string.spec.ts @@ -62,54 +62,70 @@ describe('StringSampler', () => { }, { input: { + type: 'string', + format: 'pattern', maxLength: 4, minLength: 4, - pattern: '^[0-9]+$', - type: 'string' + pattern: '^[0-9]+$' }, expected: '4444' }, { input: { + type: 'string', + format: 'pattern', minLength: 5, maxLength: 6, - pattern: '^[0-9]+$', - type: 'string' + pattern: '^[0-9]+$' }, expected: '444444' }, { input: { + type: 'string', + format: 'pattern', minLength: 5, maxLength: 100, - pattern: '^[0-9]+$', - type: 'string' + pattern: '^[0-9]+$' }, expected: '444444' }, { input: { + type: 'string', + format: 'pattern', minLength: 4, - pattern: '^[0-9]+$', - type: 'string' + pattern: '^[0-9]+$' }, expected: '44444' }, { input: { + type: 'string', + format: 'pattern', minLength: 4, - pattern: '^[0-9]{4,5}$', - type: 'string' + pattern: '^[0-9]{4,5}$' }, - expected: '4444' + expected: '0000' }, { input: { + type: 'string', + format: 'pattern', minLength: 5, - pattern: '^[0-9]{3,5}$[A-Z]{3}', - type: 'string' + pattern: '^[0-9]{3,5}[A-Z]{3}$' + }, + expected: '000AAA' + }, + { + input: { + type: 'string', + format: 'pattern', + maxLength: 4, + minLength: 4, + pattern: "[^<>%=']*$" }, - expected: '4444MMM' + expected: 'QQQQ' }, { input: { @@ -120,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', @@ -326,6 +362,17 @@ describe('StringSampler', () => { 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',