This repository has been archived by the owner on Jan 2, 2024. It is now read-only.
generated from holvonix-open/hx-node-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: experimental fuzzer for nonempty arrays (#19)
This will be superseded by a generic handler for NonEmptyArrays in io-ts-types when gcanti/io-ts-types#102 is fixed.
- Loading branch information
1 parent
5b39314
commit 7e01e15
Showing
3 changed files
with
100 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { Fuzzer } from './fuzzer'; | ||
import * as t from 'io-ts'; | ||
import { NonEmptyArray, cons } from 'fp-ts/lib/NonEmptyArray'; | ||
|
||
/** | ||
* @experimental 4.1.0 This will be superseded by a generic handler for NonEmptyArrays in io-ts-types when https://github.com/gcanti/io-ts-types/issues/102 is fixed. | ||
*/ | ||
export const nonEmptyArrayFuzzer = <T>( | ||
c: t.Type<T, unknown> | ||
): Fuzzer<NonEmptyArray<T>, unknown> => ({ | ||
id: `NonEmptyArray<${c.name}>`, | ||
idType: 'name', | ||
impl: { | ||
type: 'fuzzer', | ||
children: [c, t.array(c)], | ||
func: (ctx, n0, hc, ha) => { | ||
return cons(hc.encode([n0, ctx]) as T, ha.encode([n0, ctx]) as T[]); | ||
}, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import * as assert from 'assert'; | ||
import * as lib from '../src/experimental'; | ||
|
||
import { | ||
exampleGenerator, | ||
fuzzContext, | ||
FuzzContext, | ||
createCoreRegistry, | ||
Fuzzer, | ||
} from '../src/'; | ||
import * as t from 'io-ts'; | ||
import { nonEmptyArray } from 'io-ts-types/lib/nonEmptyArray'; | ||
import { Encode } from 'io-ts'; | ||
import { rngi } from '../src/rng'; | ||
import { isRight, Right } from 'fp-ts/lib/Either'; | ||
|
||
const count = 100; | ||
|
||
// tslint:disable-next-line:no-any | ||
const types: Array<t.Type<any>> = [ | ||
nonEmptyArray(t.string), | ||
nonEmptyArray(t.union([t.string, t.number])), | ||
t.partial({ a: nonEmptyArray(t.string) }), | ||
t.type({ a: nonEmptyArray(t.string) }), | ||
t.partial({ a: nonEmptyArray(t.union([t.string, t.number])) }), | ||
t.type({ a: nonEmptyArray(t.union([t.string, t.number])) }), | ||
t.type({ a: nonEmptyArray(t.union([t.string, t.number])) }), | ||
nonEmptyArray(t.type({ a: nonEmptyArray(t.union([t.string, t.number])) })), | ||
]; | ||
|
||
describe('experimental', () => { | ||
describe('nonEmptyArrayFuzzer', () => { | ||
for (const b of types) { | ||
describe(`\`${b.name}\` codec`, () => { | ||
let p: Encode<[number, FuzzContext], unknown>; | ||
const old: unknown[] = []; | ||
it(`loads extra fuzzers and builds an example generator`, async () => { | ||
const r = createCoreRegistry()!; | ||
const fz: Fuzzer[] = [ | ||
lib.nonEmptyArrayFuzzer(t.string), | ||
lib.nonEmptyArrayFuzzer(t.union([t.string, t.number])), | ||
lib.nonEmptyArrayFuzzer( | ||
t.type({ a: nonEmptyArray(t.union([t.string, t.number])) }) | ||
), | ||
] as Fuzzer[]; | ||
r.register(...fz); | ||
p = exampleGenerator(r, b).encode; | ||
}); | ||
it(`generates decodable examples for seeds '[0, ${count})`, () => { | ||
for (const n of new Array(count).keys()) { | ||
const v = p([rngi(n) / Math.PI, fuzzContext()]); | ||
const d = b.decode(v); | ||
assert.ok( | ||
isRight(d), | ||
`must decode ${JSON.stringify(v)}, instead ${JSON.stringify(d)}` | ||
); | ||
old.push(v); | ||
const y = b.encode((d as Right<unknown>).right); | ||
// can't use deepStrictEqual because io-ts uses {...X} to encode | ||
// certain objects, thus they don't have null prototypes. | ||
// tslint:disable-next-line:deprecation | ||
assert.deepEqual(y, v, `must encode back to ${JSON.stringify(v)}`); | ||
} | ||
}) | ||
.timeout(5000) | ||
.slow(500); | ||
it(`generates same examples 2nd time`, () => { | ||
for (const n of new Array(count).keys()) { | ||
const v = p([rngi(n) / Math.PI, fuzzContext()]); | ||
assert.deepStrictEqual(v, old[n]); | ||
} | ||
}) | ||
.timeout(5000) | ||
.slow(500); | ||
}); | ||
} | ||
}); | ||
}).timeout(1000000); |