Skip to content
This repository was archived by the owner on Jan 2, 2024. It is now read-only.

Commit 279ab9e

Browse files
committed
feat: support readonlyArray types
1 parent 03fbecf commit 279ab9e

File tree

5 files changed

+107
-29
lines changed

5 files changed

+107
-29
lines changed

README.md

+14-13
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,25 @@ function fuzz() {
3535

3636
Currently supports (and their nested closure):
3737

38-
* `t.number`
39-
* `t.string`
38+
* `t.array`
4039
* `t.boolean`
41-
* `t.union`
42-
* `t.type` (interface)
43-
* `t.partial`
40+
* `t.exact`
41+
* `t.Int`
4442
* `t.intersection`
45-
* `t.array`
43+
* `t.keyof`
44+
* `t.literal`
4645
* `t.null`
46+
* `t.number`
47+
* `t.partial`
48+
* `t.readonly`
49+
* `t.readonlyArray`
50+
* `t.string`
51+
* `t.tuple`
52+
* `t.type` (interface)
4753
* `t.undefined`
48-
* `t.void`
54+
* `t.union`
4955
* `t.unknown`
50-
* `t.Int`
51-
* `t.literal`
52-
* `t.keyof`
53-
* `t.tuple`
54-
* `t.exact`
55-
* `t.readonly`
56+
* `t.void`
5657

5758
## Use Cases
5859

src/core/core.ts

+35-15
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@ import { Fuzzer, ConcreteFuzzer, fuzzGenerator } from '../fuzzer';
33
import { isLeft, isRight } from 'fp-ts/lib/Either';
44

55
export type BasicType =
6-
| t.NumberType
6+
| t.ArrayType<t.Mixed>
77
| t.BooleanType
8-
| t.StringType
9-
| t.NullType
10-
| t.UndefinedType
11-
| t.VoidType
12-
| t.UnknownType
13-
| t.UnionType<t.Mixed[]>
8+
| t.ExactType<t.Mixed>
149
| t.InterfaceType<unknown>
15-
| t.PartialType<unknown>
16-
| t.ArrayType<t.Mixed>
1710
| t.IntersectionType<t.Mixed[]>
18-
| t.LiteralType<string | number | boolean>
1911
| t.KeyofType<{ [key: string]: unknown }>
20-
| t.TupleType<t.Mixed[]>
21-
| t.ExactType<t.Mixed>
12+
| t.LiteralType<string | number | boolean>
13+
| t.NullType
14+
| t.NumberType
15+
| t.PartialType<unknown>
16+
| t.ReadonlyArrayType<t.Mixed>
2217
| t.ReadonlyType<t.Mixed>
18+
| t.StringType
19+
| t.TupleType<t.Mixed[]>
20+
| t.UndefinedType
21+
| t.UnionType<t.Mixed[]>
22+
| t.UnknownType
23+
| t.VoidType
2324
// not yet supported:
2425
| t.AnyArrayType
2526
| t.AnyDictionaryType
26-
| t.RefinementType<t.Mixed>
27-
| t.RecursiveType<t.Mixed>
2827
| t.DictionaryType<t.Mixed, t.Mixed>
29-
| t.ReadonlyArrayType<t.Mixed>;
28+
| t.RecursiveType<t.Mixed>
29+
| t.RefinementType<t.Mixed>;
3030

3131
export type basicFuzzGenerator<
3232
T,
@@ -209,6 +209,25 @@ export function arrayFuzzer(maxLength: number = defaultMaxArrayLength) {
209209
*/
210210
export const fuzzArray = fuzzArrayWithMaxLength();
211211

212+
const fuzzReadonlyArrayWithMaxLength = (maxLength: number) => (
213+
b: t.ReadonlyArrayType<t.Mixed>
214+
): ConcreteFuzzer<unknown[]> => {
215+
return {
216+
children: [b.type],
217+
func: (n, h0) => {
218+
const ret = [];
219+
for (let index = 0; index < n % maxLength; index++) {
220+
ret.push(Object.freeze(h0.encode(n + index)));
221+
}
222+
return ret;
223+
},
224+
};
225+
};
226+
227+
export function readonlyArrayFuzzer(maxLength: number = defaultMaxArrayLength) {
228+
return gen(fuzzReadonlyArrayWithMaxLength(maxLength), 'ReadonlyArrayType');
229+
}
230+
212231
export const defaultExtraProps = { ___0000_extra_: t.number };
213232

214233
const fuzzPartialWithExtraCodec = (extra: t.Props = defaultExtraProps) => (
@@ -330,6 +349,7 @@ export const coreFuzzers = [
330349
arrayFuzzer(),
331350
gen(fuzzExact, 'ExactType'),
332351
gen(fuzzReadonly, 'ReadonlyType'),
352+
readonlyArrayFuzzer(),
333353
gen(fuzzUnion, 'UnionType'),
334354
gen(fuzzIntersection, 'IntersectionType'),
335355
gen(fuzzLiteral, 'LiteralType'),

src/registry.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { Fuzzer, ExampleGenerator, exampleGenerator } from './fuzzer';
22
import * as t from 'io-ts';
33
import { coreFuzzers, arrayFuzzer } from './core/';
4-
import { partialFuzzer, interfaceFuzzer } from './core/core';
4+
import {
5+
partialFuzzer,
6+
interfaceFuzzer,
7+
readonlyArrayFuzzer,
8+
} from './core/core';
59

610
export interface Registry {
711
register<T, U extends t.Decoder<unknown, T>>(v0: Fuzzer<T, U>): Registry;
@@ -14,6 +18,7 @@ export interface Registry {
1418

1519
export interface FluentRegistry extends Registry {
1620
withArrayFuzzer(maxLength?: number): FluentRegistry;
21+
withReadonlyArrayFuzzer(maxLength?: number): FluentRegistry;
1722
withPartialFuzzer(extra?: t.Props): FluentRegistry;
1823
withInterfaceFuzzer(extra?: t.Props): FluentRegistry;
1924
}
@@ -43,6 +48,11 @@ class FluentifiedRegistry implements FluentRegistry {
4348
return this;
4449
}
4550

51+
withReadonlyArrayFuzzer(maxLength?: number): FluentRegistry {
52+
this.register(readonlyArrayFuzzer(maxLength));
53+
return this;
54+
}
55+
4656
withPartialFuzzer(extra?: t.Props): FluentRegistry {
4757
this.register(partialFuzzer(extra));
4858
return this;

test/helpers.ts

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export const types = [
2020
t.void,
2121
t.unknown,
2222
t.array(t.string),
23+
t.readonlyArray(t.string),
24+
t.array(t.partial({ s: t.string, m: t.number })),
25+
t.readonlyArray(t.partial({ s: t.string, m: t.number })),
2326
t.Int,
2427
t.literal('hello'),
2528
t.literal(34.4),

test/test-registry.ts

+44
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ describe('registry', () => {
173173
}
174174
});
175175

176+
it(`does not affect readonly arrays`, () => {
177+
const b = t.readonlyArray(t.number);
178+
const r0 = lib.createCoreRegistry();
179+
const r = lib
180+
.fluent(r0)
181+
.withArrayFuzzer(3)
182+
.exampleGenerator(b);
183+
let ml = 0;
184+
for (let i = 0; i < 100; i++) {
185+
ml = Math.max(r.encode(i).length, ml);
186+
}
187+
assert.ok(ml > 3);
188+
});
189+
176190
it(`overrides apply to the underlying registry`, () => {
177191
const b = t.array(t.number);
178192
const r0 = lib.createCoreRegistry();
@@ -185,6 +199,36 @@ describe('registry', () => {
185199
});
186200
});
187201

202+
describe('#withReadonlyArrayFuzzer', () => {
203+
describe('on the core registry', () => {
204+
it(`overrides the array fuzzer max length`, () => {
205+
const b = t.readonlyArray(t.number);
206+
const r0 = lib.createCoreRegistry();
207+
const r = lib
208+
.fluent(r0)
209+
.withReadonlyArrayFuzzer(3)
210+
.exampleGenerator(b);
211+
for (let i = 0; i < 100; i++) {
212+
assert.ok(r.encode(i).length <= 3);
213+
}
214+
});
215+
216+
it(`does not affect non-readonly arrays`, () => {
217+
const b = t.array(t.number);
218+
const r0 = lib.createCoreRegistry();
219+
const r = lib
220+
.fluent(r0)
221+
.withReadonlyArrayFuzzer(3)
222+
.exampleGenerator(b);
223+
let ml = 0;
224+
for (let i = 0; i < 100; i++) {
225+
ml = Math.max(r.encode(i).length, ml);
226+
}
227+
assert.ok(ml > 3);
228+
});
229+
});
230+
});
231+
188232
describe('#withPartialFuzzer', () => {
189233
describe('on the core registry', () => {
190234
it(`overrides the partial object extra properties`, () => {

0 commit comments

Comments
 (0)