diff --git a/package.json b/package.json index 1f781ed..25e982a 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,7 @@ "name": "fast-check-io-ts", "version": "0.4.0", "description": "io-ts codec to fast-check arbitrary mapping", - "files": [ - "lib" - ], + "files": ["lib"], "main": "lib/index.js", "typings": "lib/index.d.ts", "repository": { @@ -27,14 +25,7 @@ "lint": "tslint -p tsconfig.json src/*.ts", "dtslint": "dtslint dtslint" }, - "keywords": [ - "fast-check", - "io-ts", - "typescript", - "arbitrary", - "generative", - "testing" - ], + "keywords": ["fast-check", "io-ts", "typescript", "arbitrary", "generative", "testing"], "author": "Giovanni Gonzaga ", "license": "MIT", "devDependencies": { @@ -49,12 +40,13 @@ "rimraf": "^2.6.3", "ts-jest": "^24.0.2", "tslint": "^5.18.0", - "typescript": "^3.5.3" + "typescript": "^3.5.3", + "io-ts-types": "^0.5.6" }, "peerDependencies": { "fast-check": "^1.16.0", - "io-ts": "^2.0.0", - "fp-ts": "^2.0.0" + "fp-ts": "^2.0.0", + "io-ts": "^2.0.0" }, "jest": { "preset": "ts-jest" diff --git a/src/index.ts b/src/index.ts index dce67cb..9043385 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,6 +32,10 @@ export type HasArbitrary = | IntersectionType | BrandedType; +interface Overrides { + [key: string]: fc.Arbitrary; +} + function getProps(codec: t.InterfaceType | t.ExactType | t.PartialType): t.Props { switch (codec._tag) { case 'InterfaceType': @@ -44,11 +48,11 @@ function getProps(codec: t.InterfaceType | t.ExactType | t.PartialType const objectTypes = ['ExactType', 'InterfaceType', 'PartialType']; -export function getArbitrary(codec: T): fc.Arbitrary> { +export function getArbitrary(codec: T, overrides: Overrides = {}): fc.Arbitrary> { const type: HasArbitrary = codec as any; switch (type._tag) { case 'UnknownType': - return fc.anything(); + return fc.anything() as any; case 'UndefinedType': case 'VoidType': return fc.constant(undefined) as any; @@ -71,19 +75,28 @@ export function getArbitrary(codec: T): fc.Arbitrary getArbitrary(codec as any, overrides)) as any) as any; case 'TupleType': - return (fc.tuple as any)(...type.types.map(getArbitrary)); + return (fc.tuple as any)(...type.types.map(codec => getArbitrary(codec, overrides))); case 'UnionType': - return fc.oneof(...type.types.map(getArbitrary)) as any; + return fc.oneof(...type.types.map(codec => getArbitrary(codec, overrides))) as any; case 'IntersectionType': const isObjectIntersection = objectTypes.includes(type.types[0]._tag); return isObjectIntersection - ? (fc.tuple as any)(...type.types.map(t => getArbitrary(t))) + ? (fc.tuple as any)(...type.types.map(t => getArbitrary(t, overrides))) .map((values: Array) => Object.assign({}, ...values)) .filter(type.is) - : fc.oneof(...type.types.map(t => getArbitrary(t))).filter(type.is); + : fc.oneof(...type.types.map(t => getArbitrary(t, overrides))).filter(type.is); case 'RefinementType': return getArbitrary(type.type).filter(type.predicate) as any; + default: + // if we cannot find the type, check whether it has been passed as an + // override and use that instead + const typeName = (type as any).name; + if (typeName && overrides[typeName] !== undefined) { + return overrides[typeName]; + } + // failing that, throw an error? + throw Error(`Could not create an Arbitrary for ${typeName}. Consider passing in a custom override?`); } } diff --git a/test/index.test.ts b/test/index.test.ts index 26a06af..a4822b5 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,10 +1,14 @@ import * as fc from 'fast-check'; import * as t from 'io-ts'; import { getArbitrary, HasArbitrary } from '../src'; +import { date } from 'io-ts-types/lib/date'; + +// pass +const overrides = { Date: fc.date() }; function test(codec: T): void { it(codec.name, () => { - fc.assert(fc.property(getArbitrary(codec), codec.is)); + fc.assert(fc.property(getArbitrary(codec, overrides), codec.is)); }); } @@ -27,3 +31,4 @@ test(t.intersection([t.type({ foo: t.string }), t.partial({ bar: t.number })])); test(t.intersection([t.type({ foo: t.string }), t.type({ bar: t.number })])); test(t.intersection([t.array(t.string), t.array(t.number)])); test(t.record(t.string, t.number)); +test(t.type({ date }));