Repository: gcanti/fp-ts
Pull request #478 (2018-06-10 07:41:45)

add more tests


Patch:
diff --git a/docs/Array.md b/docs/Array.md
index abe624fe..5db9e091 100644
--- a/docs/Array.md
+++ b/docs/Array.md
@@ -231,7 +231,39 @@ _Signature_
 
 _Description_
 
-Lazy version of `fold`
+Lazy version of [fold](#fold)
+
+### foldr
+
+_function_
+
+_since 1.7.0_
+
+_Signature_
+
+```ts
+<A, B>(as: Array<A>, b: B, cons: (init: Array<A>, last: A) => B): B
+```
+
+_Description_
+
+Break an array into its initial elements and the last element
+
+### foldrL
+
+_function_
+
+_since 1.7.0_
+
+_Signature_
+
+```ts
+<A, B>(as: Array<A>, nil: () => B, cons: (init: Array<A>, last: A) => B): B
+```
+
+_Description_
+
+Lazy version of [foldr](#foldr)
 
 ### getMonoid
 
diff --git a/docs/Random.md b/docs/Random.md
index 09dd5a59..001a73fe 100644
--- a/docs/Random.md
+++ b/docs/Random.md
@@ -5,6 +5,41 @@ title: Module Random
 
 [Source](https://github.com/gcanti/fp-ts/blob/master/src/Random.ts)
 
+## Constants
+
+### random
+
+_constant_
+
+_since 1.0.0_
+
+_Signature_
+
+```ts
+random: IO<number>
+```
+
+_Description_
+
+Returns a random number between 0 (inclusive) and 1 (exclusive). This is a direct wrapper around JavaScript's
+`Math.random()`.
+
+### randomBool
+
+_constant_
+
+_since 1.0.0_
+
+_Signature_
+
+```ts
+randomBool: IO<boolean>
+```
+
+_Description_
+
+Returns a random boolean value with an equal chance of being `true` or `false`
+
 ## Functions
 
 ### randomInt
@@ -16,7 +51,7 @@ _since 1.0.0_
 _Signature_
 
 ```ts
-;(low: number, high: number): IO<number> => random.map(n => Math.floor((high - low + 1) * n + low))
+(low: number, high: number): IO<number>
 ```
 
 _Description_
@@ -34,7 +69,7 @@ _since 1.0.0_
 _Signature_
 
 ```ts
-;(min: number, max: number): IO<number> => random.map(n => (max - min + 1) * n + min)
+(min: number, max: number): IO<number>
 ```
 
 _Description_
diff --git a/package.json b/package.json
index 48e963a4..fdc7ff75 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,9 @@
       }
     },
     "collectCoverageFrom": [
-      "src/**/*.{ts}"
+      "src/**/*.{ts}",
+      "!src/Free.ts",
+      "!src/Store.ts"
     ],
     "transform": {
       "^.+\\.tsx?$": "ts-jest"
@@ -74,6 +76,14 @@
     "moduleFileExtensions": [
       "ts",
       "js"
-    ]
+    ],
+    "coverageThreshold": {
+      "global": {
+        "branches": 100,
+        "functions": 100,
+        "lines": 100,
+        "statements": 0
+      }
+    }
   }
 }
diff --git a/src/Array.ts b/src/Array.ts
index 05806b36..a19b4d20 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -234,7 +234,7 @@ export const fold = <A, B>(as: Array<A>, b: B, cons: (head: A, tail: Array<A>) =
 }
 
 /**
- * Lazy version of `fold`
+ * Lazy version of {@link fold}
  * @function
  * @since 1.0.0
  */
@@ -244,21 +244,27 @@ export const foldL = <A, B>(as: Array<A>, nil: () => B, cons: (head: A, tail: Ar
 
 /**
  * Break an array into its initial elements and the last element
+ * @function
+ * @since 1.7.0
  * @param as
  * @param b
  * @param cons
  */
-export const foldr = <A, B>(as: Array<A>, b: B, cons: (init: Array<A>, last: A) => B): B =>
-  isEmpty(as) ? b : cons(as.slice(0, as.length - 1), as[as.length - 1])
+export const foldr = <A, B>(as: Array<A>, b: B, cons: (init: Array<A>, last: A) => B): B => {
+  return isEmpty(as) ? b : cons(as.slice(0, as.length - 1), as[as.length - 1])
+}
 
 /**
- * Lazy version of `foldr`
+ * Lazy version of {@link foldr}
+ * @function
+ * @since 1.7.0
  * @param as
  * @param nil
  * @param cons
  */
-export const foldrL = <A, B>(as: Array<A>, nil: () => B, cons: (init: Array<A>, last: A) => B): B =>
-  isEmpty(as) ? nil() : cons(as.slice(0, as.length - 1), as[as.length - 1])
+export const foldrL = <A, B>(as: Array<A>, nil: () => B, cons: (init: Array<A>, last: A) => B): B => {
+  return isEmpty(as) ? nil() : cons(as.slice(0, as.length - 1), as[as.length - 1])
+}
 
 /**
  * Same as `reduce` but it carries over the intermediate steps
diff --git a/src/Random.ts b/src/Random.ts
index 1843529d..ecf11902 100644
--- a/src/Random.ts
+++ b/src/Random.ts
@@ -5,6 +5,8 @@ import { IO } from './IO'
 /**
  * Returns a random number between 0 (inclusive) and 1 (exclusive). This is a direct wrapper around JavaScript's
  * `Math.random()`.
+ * @constant
+ * @since 1.0.0
  */
 export const random: IO<number> = new IO(() => Math.random())
 
@@ -15,8 +17,9 @@ export const random: IO<number> = new IO(() => Math.random())
  * @function
  * @since 1.0.0
  */
-export const randomInt = (low: number, high: number): IO<number> =>
-  random.map(n => Math.floor((high - low + 1) * n + low))
+export const randomInt = (low: number, high: number): IO<number> => {
+  return random.map(n => Math.floor((high - low + 1) * n + low))
+}
 
 /**
  * Returns a random number between a minimum value (inclusive) and a maximum value (exclusive). It is unspecified what
@@ -24,7 +27,13 @@ export const randomInt = (low: number, high: number): IO<number> =>
  * @function
  * @since 1.0.0
  */
-export const randomRange = (min: number, max: number): IO<number> => random.map(n => (max - min + 1) * n + min)
+export const randomRange = (min: number, max: number): IO<number> => {
+  return random.map(n => (max - min) * n + min)
+}
 
-/** Returns a random boolean value with an equal chance of being `true` or `false` */
+/**
+ * Returns a random boolean value with an equal chance of being `true` or `false`
+ * @constant
+ * @since 1.0.0
+ */
 export const randomBool: IO<boolean> = random.map(n => n < 0.5)


Test patch:
diff --git a/test/BooleanAlgebra.ts b/test/BooleanAlgebra.ts
new file mode 100644
index 00000000..4cd0b420
--- /dev/null
+++ b/test/BooleanAlgebra.ts
@@ -0,0 +1,89 @@
+import * as assert from 'assert'
+import {
+  booleanAlgebraBoolean,
+  booleanAlgebraVoid,
+  getFunctionBooleanAlgebra,
+  getDualBooleanAlgebra
+} from '../src/BooleanAlgebra'
+
+describe('BooleanAlgebra', () => {
+  it('booleanAlgebraBoolean', () => {
+    const BA = booleanAlgebraBoolean
+    assert.strictEqual(BA.implies(true, true), true)
+    assert.strictEqual(BA.implies(true, false), false)
+    assert.strictEqual(BA.implies(false, true), true)
+    assert.strictEqual(BA.implies(false, false), true)
+
+    assert.strictEqual(BA.join(true, true), true)
+    assert.strictEqual(BA.join(true, false), true)
+    assert.strictEqual(BA.join(false, true), true)
+    assert.strictEqual(BA.join(false, false), false)
+
+    assert.strictEqual(BA.meet(true, true), true)
+    assert.strictEqual(BA.meet(true, false), false)
+
+    assert.strictEqual(BA.not(true), false)
+    assert.strictEqual(BA.not(false), true)
+
+    assert.strictEqual(BA.one, true)
+    assert.strictEqual(BA.zero, false)
+  })
+
+  it('booleanAlgebraVoid', () => {
+    const BA = booleanAlgebraVoid
+    assert.strictEqual(BA.implies(undefined, undefined), undefined)
+
+    assert.strictEqual(BA.join(undefined, undefined), undefined)
+
+    assert.strictEqual(BA.meet(undefined, undefined), undefined)
+
+    assert.strictEqual(BA.not(undefined), undefined)
+
+    assert.strictEqual(BA.one, undefined)
+    assert.strictEqual(BA.zero, undefined)
+  })
+
+  it('getFunctionBooleanAlgebra', () => {
+    const BA = getFunctionBooleanAlgebra(booleanAlgebraBoolean)<number>()
+    const f = (n: number) => n >= 0
+    const g = (n: number) => n < 2
+    assert.strictEqual(BA.implies(f, g)(1), true)
+    assert.strictEqual(BA.implies(f, g)(-1), true)
+
+    assert.strictEqual(BA.join(f, g)(1), true)
+    assert.strictEqual(BA.join(f, g)(-1), true)
+
+    assert.strictEqual(BA.meet(f, g)(1), true)
+    assert.strictEqual(BA.meet(f, g)(-1), false)
+
+    assert.strictEqual(BA.not(f)(1), false)
+    assert.strictEqual(BA.not(f)(-1), true)
+
+    assert.strictEqual(BA.one(1), true)
+    assert.strictEqual(BA.one(-1), true)
+    assert.strictEqual(BA.zero(1), false)
+    assert.strictEqual(BA.zero(-1), false)
+  })
+
+  it('getDualBooleanAlgebra', () => {
+    const BA = getDualBooleanAlgebra(booleanAlgebraBoolean)
+    assert.strictEqual(BA.implies(true, true), true)
+    assert.strictEqual(BA.implies(true, false), false)
+    assert.strictEqual(BA.implies(false, true), true)
+    assert.strictEqual(BA.implies(false, false), true)
+
+    assert.strictEqual(BA.join(true, true), true)
+    assert.strictEqual(BA.join(true, false), false)
+    assert.strictEqual(BA.join(false, true), false)
+    assert.strictEqual(BA.join(false, false), false)
+
+    assert.strictEqual(BA.meet(true, true), true)
+    assert.strictEqual(BA.meet(true, false), true)
+
+    assert.strictEqual(BA.not(true), false)
+    assert.strictEqual(BA.not(false), true)
+
+    assert.strictEqual(BA.one, false)
+    assert.strictEqual(BA.zero, true)
+  })
+})
diff --git a/test/BoundedDistributiveLattice.ts b/test/BoundedDistributiveLattice.ts
new file mode 100644
index 00000000..f29a9aab
--- /dev/null
+++ b/test/BoundedDistributiveLattice.ts
@@ -0,0 +1,13 @@
+import * as assert from 'assert'
+import { getMinMaxBoundedDistributiveLattice } from '../src/BoundedDistributiveLattice'
+import { ordNumber } from '../src/Ord'
+
+describe('BoundedDistributiveLattice', () => {
+  it('getMinMaxBoundedDistributiveLattice', () => {
+    const BDL = getMinMaxBoundedDistributiveLattice(ordNumber)(0, 1)
+    assert.strictEqual(BDL.join(0.2, 0.4), 0.4)
+    assert.strictEqual(BDL.meet(0.2, 0.4), 0.2)
+    assert.strictEqual(BDL.one, 1)
+    assert.strictEqual(BDL.zero, 0)
+  })
+})
diff --git a/test/Chain.ts b/test/Chain.ts
new file mode 100644
index 00000000..adbfc10a
--- /dev/null
+++ b/test/Chain.ts
@@ -0,0 +1,12 @@
+import * as assert from 'assert'
+import { flatten } from '../src/Chain'
+import { option, some, none } from '../src/Option'
+
+describe('Chain', () => {
+  it('flatten', () => {
+    const f = flatten(option)
+    assert.deepEqual(f(some(some(1))), some(1))
+    assert.deepEqual(f(some(none)), none)
+    assert.deepEqual(f(none), none)
+  })
+})
diff --git a/test/Console.ts b/test/Console.ts
new file mode 100644
index 00000000..f36dada6
--- /dev/null
+++ b/test/Console.ts
@@ -0,0 +1,48 @@
+import * as assert from 'assert'
+import { log, info, error, warn } from '../src/Console'
+
+describe('Console', () => {
+  it('log', () => {
+    const log_ = console.log
+    const logger: Array<any> = []
+    console.log = (a: any) => {
+      logger.push(a)
+    }
+    log('log').run()
+    assert.deepEqual(logger, ['log'])
+    console.log = log_
+  })
+
+  it('info', () => {
+    const info_ = console.info
+    const logger: Array<any> = []
+    console.info = (a: any) => {
+      logger.push(a)
+    }
+    info('info').run()
+    assert.deepEqual(logger, ['info'])
+    console.info = info_
+  })
+
+  it('error', () => {
+    const error_ = console.error
+    const logger: Array<any> = []
+    console.error = (a: any) => {
+      logger.push(a)
+    }
+    error('error').run()
+    assert.deepEqual(logger, ['error'])
+    console.error = error_
+  })
+
+  it('warn', () => {
+    const warn_ = console.warn
+    const logger: Array<any> = []
+    console.warn = (a: any) => {
+      logger.push(a)
+    }
+    warn('warn').run()
+    assert.deepEqual(logger, ['warn'])
+    console.warn = warn_
+  })
+})
diff --git a/test/Extend.ts b/test/Extend.ts
new file mode 100644
index 00000000..43b4e72b
--- /dev/null
+++ b/test/Extend.ts
@@ -0,0 +1,11 @@
+import * as assert from 'assert'
+import { duplicate } from '../src/Extend'
+import { option, some, none } from '../src/Option'
+
+describe('Extend', () => {
+  it('duplicate', () => {
+    const f = duplicate(option)
+    assert.deepEqual(f(none), none)
+    assert.deepEqual(f(some(1)), some(some(1)))
+  })
+})
diff --git a/test/Profunctor.ts b/test/Profunctor.ts
new file mode 100644
index 00000000..272fe5ca
--- /dev/null
+++ b/test/Profunctor.ts
@@ -0,0 +1,49 @@
+import * as assert from 'assert'
+import { rmap, lmap, Profunctor2 } from '../src/Profunctor'
+
+declare module '../src/HKT' {
+  interface URI2HKT2<L, A> {
+    Fun: Fun<L, A>
+  }
+}
+
+const URI = 'Fun'
+
+type URI = typeof URI
+
+class Fun<L, A> {
+  readonly _A!: A
+  readonly _L!: L
+  readonly _URI!: URI
+  constructor(readonly run: (l: L) => A) {}
+}
+
+const map = <L, A, B>(fa: Fun<L, A>, f: (a: A) => B): Fun<L, B> => {
+  return new Fun(l => f(fa.run(l)))
+}
+
+const promap = <A, B, C, D>(fbc: Fun<B, C>, f: (a: A) => B, g: (c: C) => D): Fun<A, D> => {
+  return new Fun(a => g(fbc.run(f(a))))
+}
+
+const profunctorFun: Profunctor2<URI> = {
+  URI,
+  map,
+  promap
+}
+
+describe('Profunctor', () => {
+  it('lmap', () => {
+    const fbc = new Fun((s: string): number => s.length)
+    const f = lmap(profunctorFun)
+    const fac = f(fbc, (s: string) => s + '!')
+    assert.strictEqual(fac.run('foo'), 4)
+  })
+
+  it('rmap', () => {
+    const fbc = new Fun((s: string): number => s.length)
+    const f = rmap(profunctorFun)
+    const fac = f(fbc, n => n >= 0)
+    assert.strictEqual(fac.run('foo'), true)
+  })
+})
diff --git a/test/Random.ts b/test/Random.ts
new file mode 100644
index 00000000..fc153f0c
--- /dev/null
+++ b/test/Random.ts
@@ -0,0 +1,32 @@
+import * as assert from 'assert'
+import { random, randomInt, randomBool, randomRange } from '../src/Random'
+
+describe('Random', () => {
+  it('random', () => {
+    const n = random.run()
+    assert.strictEqual(typeof n, 'number')
+  })
+
+  it('randomInt', () => {
+    const n = randomInt(0, 10).run()
+    assert.strictEqual(typeof n, 'number')
+    assert.strictEqual(n % 1 === 0, true)
+    assert.strictEqual(n >= 0, true)
+    assert.strictEqual(n <= 10, true)
+  })
+
+  it('randomRange', () => {
+    for (let i = 0; i < 10; i++) {
+      const n = randomRange(0, 10).run()
+      console.log(n)
+      assert.strictEqual(typeof n, 'number')
+      assert.strictEqual(n >= 0, true)
+      assert.strictEqual(n < 10, true)
+    }
+  })
+
+  it('randomBool', () => {
+    const b = randomBool.run()
+    assert.strictEqual(typeof b, 'boolean')
+  })
+})
diff --git a/test/Trace.ts b/test/Trace.ts
new file mode 100644
index 00000000..f644a509
--- /dev/null
+++ b/test/Trace.ts
@@ -0,0 +1,51 @@
+import * as assert from 'assert'
+import { trace, spy, traceA, traceM } from '../src/Trace'
+import { some, option } from '../src/Option'
+
+describe('Trace', () => {
+  it('trace', () => {
+    const log_ = console.log
+    const logger: Array<any> = []
+    console.log = (a: any) => {
+      logger.push(a)
+    }
+    trace('trace', () => 1)
+    assert.deepEqual(logger, ['trace'])
+    console.log = log_
+  })
+
+  it('spy', () => {
+    const log_ = console.log
+    const logger: Array<any> = []
+    console.log = (a: any) => {
+      logger.push(a)
+    }
+    spy(some(1))
+    assert.deepEqual(logger, [some(1)])
+    console.log = log_
+  })
+
+  it('traceA', () => {
+    const log_ = console.log
+    const logger: Array<any> = []
+    console.log = (a: any) => {
+      logger.push(a)
+    }
+    const x = traceA(option)('traceA')
+    assert.deepEqual(logger, ['traceA'])
+    assert.deepEqual(x, some(undefined))
+    console.log = log_
+  })
+
+  it('traceM', () => {
+    const log_ = console.log
+    const logger: Array<any> = []
+    console.log = (a: any) => {
+      logger.push(a)
+    }
+    const x = traceM(option)('traceM')
+    assert.deepEqual(logger, ['traceM'])
+    assert.deepEqual(x, some('traceM'))
+    console.log = log_
+  })
+})