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

Commit 883ec4b

Browse files
committed
feat: support exact types
1 parent 15ae0cd commit 883ec4b

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Currently supports (and their nested closure):
5151
* `t.literal`
5252
* `t.keyof`
5353
* `t.tuple`
54+
* `t.exact`
5455

5556
## Use Cases
5657

src/core/core.ts

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as t from 'io-ts';
22
import { Fuzzer, ConcreteFuzzer, fuzzGenerator } from '../fuzzer';
3-
import { isLeft } from 'fp-ts/lib/Either';
3+
import { isLeft, isRight } from 'fp-ts/lib/Either';
44

55
export type BasicType =
66
| t.NumberType
@@ -18,15 +18,15 @@ export type BasicType =
1818
| t.LiteralType<string | number | boolean>
1919
| t.KeyofType<{ [key: string]: unknown }>
2020
| t.TupleType<t.Mixed[]>
21+
| t.ExactType<t.Mixed>
2122
// not yet supported:
2223
| t.AnyArrayType
2324
| t.AnyDictionaryType
2425
| t.RefinementType<t.Mixed>
2526
| t.RecursiveType<t.Mixed>
2627
| t.DictionaryType<t.Mixed, t.Mixed>
2728
| t.ReadonlyType<t.Mixed>
28-
| t.ReadonlyArrayType<t.Mixed>
29-
| t.ExactType<t.Mixed>;
29+
| t.ReadonlyArrayType<t.Mixed>;
3030

3131
export type basicFuzzGenerator<
3232
T,
@@ -156,6 +156,21 @@ export function fuzzTuple(
156156
};
157157
}
158158

159+
export function fuzzExact(b: t.ExactC<t.HasProps>): ConcreteFuzzer<unknown> {
160+
return {
161+
children: [b.type],
162+
func: (n, h0) => {
163+
const r = h0.encode(n);
164+
const d = b.decode(r);
165+
/* istanbul ignore if */
166+
if (!isRight(d)) {
167+
throw new Error(`codec failed to decode underlying example`);
168+
}
169+
return d.right;
170+
},
171+
};
172+
}
173+
159174
export const defaultMaxArrayLength = 13;
160175

161176
const fuzzArrayWithMaxLength = (maxLength: number = defaultMaxArrayLength) => (
@@ -291,19 +306,20 @@ export function fuzzIntersection(
291306

292307
export const coreFuzzers = [
293308
concrete(fuzzNumber, 'NumberType'),
309+
concreteNamed(fuzzInt, 'Int'),
294310
concrete(fuzzBoolean, 'BooleanType'),
295311
concrete(fuzzString, 'StringType'),
296312
concrete(fuzzNull, 'NullType'),
297313
concrete(fuzzUndefined, 'UndefinedType'),
298314
concrete(fuzzVoid, 'VoidType'),
299315
concrete(fuzzUnknown, 'UnknownType'),
300-
gen(fuzzUnion, 'UnionType'),
301316
interfaceFuzzer(),
302317
partialFuzzer(),
303318
arrayFuzzer(),
319+
gen(fuzzExact, 'ExactType'),
320+
gen(fuzzUnion, 'UnionType'),
304321
gen(fuzzIntersection, 'IntersectionType'),
305322
gen(fuzzLiteral, 'LiteralType'),
306323
gen(fuzzKeyof, 'KeyofType'),
307324
gen(fuzzTuple, 'TupleType'),
308-
concreteNamed(fuzzInt, 'Int'),
309325
];

test/helpers.ts

+16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@ export const types = [
1111
t.type({ s: t.string, m: t.number, ___0000_extra_: t.string }),
1212
t.partial({ s: t.string, m: t.number }),
1313
t.partial({ s: t.string, m: t.number, ___0000_extra_: t.boolean }),
14+
t.exact(t.type({ s: t.string, m: t.number })),
15+
t.exact(t.type({ s: t.string, m: t.number, ___0000_extra_: t.string })),
16+
t.exact(t.partial({ s: t.string, m: t.number })),
17+
t.exact(t.partial({ s: t.string, m: t.number, ___0000_extra_: t.boolean })),
18+
t.exact(
19+
t.intersection([
20+
t.type({ s: t.string, m: t.number, ___0000_extra_: t.boolean }),
21+
t.type({ s: t.string, j: t.boolean }),
22+
])
23+
),
24+
t.exact(
25+
t.intersection([
26+
t.type({ s: t.string, m: t.number, ___0000_extra_: t.boolean }),
27+
t.type({ s2: t.string, j: t.boolean }),
28+
])
29+
),
1430
t.null,
1531
t.undefined,
1632
t.void,

test/test-fuzzer.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as lib from '../src/fuzzer';
44
import { types, unknownTypes, runtimeFailTypes } from './helpers';
55
import { createCoreRegistry } from '../src/registry';
66
import { isRight } from 'fp-ts/lib/Either';
7+
import { inspect } from 'util';
78

89
describe('fuzzer', () => {
910
describe('#exampleGenerator', () => {
@@ -31,7 +32,8 @@ describe('fuzzer', () => {
3132
for (const b of types) {
3233
it(`can fuzz \`${b.name}\` type`, () => {
3334
const r = createCoreRegistry();
34-
assert.ok(isRight(b.decode(lib.exampleOf(b, r, 0))));
35+
const ex = lib.exampleOf(b, r, 0);
36+
assert.ok(isRight(b.decode(ex)), inspect(ex));
3537
});
3638
}
3739
for (const b of runtimeFailTypes) {

0 commit comments

Comments
 (0)