From aa2e76fc58c6713d1f92fdaf8702d76666e52376 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 19 Mar 2019 08:37:40 +0100 Subject: [PATCH] add property test --- jest.config.js | 3 ++- package-lock.json | 35 ++++++++++++++++++++++++++- package.json | 1 + test/Apply.ts | 26 ++++++++++++++++---- test/property-test/NonEmptyArray2v.ts | 9 +++++++ test/property-test/Option.ts | 26 ++++++++++++++++++++ 6 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 test/property-test/NonEmptyArray2v.ts create mode 100644 test/property-test/Option.ts diff --git a/jest.config.js b/jest.config.js index 0c89b7e12..9b868ff73 100644 --- a/jest.config.js +++ b/jest.config.js @@ -15,5 +15,6 @@ module.exports = { lines: 100, statements: 100 } - } + }, + modulePathIgnorePatterns: ['property-test'] } diff --git a/package-lock.json b/package-lock.json index b3043d90e..591ed3732 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "fp-ts", - "version": "1.14.3", + "version": "1.14.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2045,6 +2045,16 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, + "fast-check": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-1.12.1.tgz", + "integrity": "sha512-JRoqLwalxb46RX/iVJyvErHXqojVggXqg+jRAWU2BfuLtxZYq5uetibLLousdUKcX+u8jFXyIn7ezSG1Rab/lQ==", + "dev": true, + "requires": { + "lorem-ipsum": "~1.0.6", + "pure-rand": "^1.6.2" + } + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -4610,6 +4620,23 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lorem-ipsum": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/lorem-ipsum/-/lorem-ipsum-1.0.6.tgz", + "integrity": "sha512-Rx4XH8X4KSDCKAVvWGYlhAfNqdUP5ZdT4rRyf0jjrvWgtViZimDIlopWNfn/y3lGM5K4uuiAoY28TaD+7YKFrQ==", + "dev": true, + "requires": { + "minimist": "~1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -5447,6 +5474,12 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "pure-rand": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-1.6.2.tgz", + "integrity": "sha512-HNwHOH63m7kCxe0kWEe5jSLwJiL2N83RUUN8POniFuZS+OsbFcMWlvXgxIU2nwKy2zYG2bQan40WBNK4biYPRg==", + "dev": true + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", diff --git a/package.json b/package.json index 6912d18c0..29291079b 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "doctoc": "^1.4.0", "doctrine": "2.0.0", "dtslint": "github:gcanti/dtslint", + "fast-check": "^1.12.1", "glob": "^7.1.3", "jest": "^23.6.0", "mocha": "^5.2.0", diff --git a/test/Apply.ts b/test/Apply.ts index d029eb0ba..9e773508f 100644 --- a/test/Apply.ts +++ b/test/Apply.ts @@ -1,7 +1,12 @@ import * as assert from 'assert' import { applyFirst, applySecond, liftA2, liftA3, liftA4, sequenceT, sequenceS } from '../src/Apply' import { either, left, right } from '../src/Either' -import { none, option, some } from '../src/Option' +import { none, option, some, isSome, isNone } from '../src/Option' +import * as fc from 'fast-check' +import { getSome } from './property-test/Option' +import { nonEmptyArray } from './property-test/NonEmptyArray2v' +import { catOptions, getSetoid } from '../src/Array' +import { fromEquals } from '../src/Setoid' describe('Apply', () => { const r1 = right(1) @@ -64,13 +69,24 @@ describe('Apply', () => { it('sequenceT', () => { const sequenceTOption = sequenceT(option) - const sequenceTEither = sequenceT(either) assert.deepStrictEqual(sequenceTOption(some(1)), some([1])) assert.deepStrictEqual(sequenceTOption(some(1), some('2')), some([1, '2'])) assert.deepStrictEqual(sequenceTOption(some(1), some('2'), none), none) - assert.deepStrictEqual(sequenceTEither(right(1)), right([1])) - assert.deepStrictEqual(sequenceTEither(right(1), right('2')), right([1, '2'])) - assert.deepStrictEqual(sequenceTEither(right(1), right('2'), left('foo')), left('foo')) + + const S = getSetoid(fromEquals((x, y) => x === y)) + const somes = getSome(fc.oneof(fc.string(), fc.integer())) + const allSomesInput = nonEmptyArray(somes) + const maybeNoneInput = nonEmptyArray(fc.oneof(fc.constant(none), somes)) + const input = fc.oneof(allSomesInput, maybeNoneInput) + fc.assert( + fc.property(input, options => { + const x = sequenceTOption(...(options as any)) + return ( + (options.every(isSome) && x.isSome() && S.equals(x.value as any, catOptions(options))) || + (options.some(isNone) && x.isNone()) + ) + }) + ) }) it('sequenceS', () => { diff --git a/test/property-test/NonEmptyArray2v.ts b/test/property-test/NonEmptyArray2v.ts new file mode 100644 index 000000000..80aec0ca8 --- /dev/null +++ b/test/property-test/NonEmptyArray2v.ts @@ -0,0 +1,9 @@ +import * as fc from 'fast-check' +import { NonEmptyArray } from '../../src/NonEmptyArray2v' + +/** + * Returns an `Arbitrary` that yelds a non empty array + */ +export function nonEmptyArray(arb: fc.Arbitrary): fc.Arbitrary> { + return fc.array(arb, 1, 100) as any +} diff --git a/test/property-test/Option.ts b/test/property-test/Option.ts new file mode 100644 index 000000000..cfe1d7517 --- /dev/null +++ b/test/property-test/Option.ts @@ -0,0 +1,26 @@ +import * as fc from 'fast-check' +import { Option, some, none } from '../../src/Option' + +/** + * Returns an `Arbitrary` that yelds only `some`s + * @since 0.0.2 + */ +export function getSome(arb: fc.Arbitrary): fc.Arbitrary> { + return arb.map(some) +} + +/** + * Returns an `Arbitrary` that yelds only `none`s + * @since 0.0.2 + */ +export function getNone(): fc.Arbitrary> { + return fc.constant(none) +} + +/** + * Returns an `Arbitrary` that yelds both `some`s and `none`s + * @since 0.0.2 + */ +export function getOption(arb: fc.Arbitrary): fc.Arbitrary> { + return fc.oneof(getNone(), getSome(arb)) +}