Repository: dubzzz/fast-check
Pull request #1801 (2021-04-27 06:44:34)

🚚 Move `boolean` arbitrary into /arbitrary
<!-- Why is this PR for? -->
<!-- Describe the reason why you opened this PR or give a link towards the associated issue. -->

## In a nutshell

❌ New feature
❌ Fix an issue
❌ Documentation improvement
✔️ Other: *please explain*

(✔️: yes, ❌: no)

## Potential impacts

None

codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/dubzzz/fast-check/pr/1801/builds/124211) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 80e9a8353a73951814c742a6ae6b4d369927265a:

|Sandbox| Source |
|--|--|
|[Vanilla](https://codesandbox.io/s/vanilla-d8r01)| Configuration |
|[fast-check-examples](https://codesandbox.io/s/fast-check-examples-q0ehm)| Configuration |

codecov[bot]: # [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1801?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) Report
> Merging [#1801](https://codecov.io/gh/dubzzz/fast-check/pull/1801?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (80e9a83) into [main](https://codecov.io/gh/dubzzz/fast-check/commit/25ded1d8fe1c025d7010b98474d207464b00f8d7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (25ded1d) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/dubzzz/fast-check/pull/1801/graphs/tree.svg?width=650&height=150&src=pr&token=fRi2fJN730&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)](https://codecov.io/gh/dubzzz/fast-check/pull/1801?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)

```diff
@@           Coverage Diff           @@
##             main    #1801   +/-   ##
=======================================
  Coverage   97.24%   97.24%           
=======================================
  Files         129      129           
  Lines        3735     3740    +5     
  Branches      738      740    +2     
=======================================
+ Hits         3632     3637    +5     
  Misses         99       99           
  Partials        4        4           
```

| Flag | Coverage Δ | |
|---|---|---|
| unit-tests | `97.24% <100.00%> (+<0.01%)` | :arrow_up: |
| unit-tests-10.x-Linux | `?` | |
| unit-tests-12.x-Linux | `?` | |
| unit-tests-14.x-Linux | `97.24% <100.00%> (+0.03%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dubzzz/fast-check/pull/1801?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) | Coverage Δ | |
|---|---|---|
| [src/arbitrary/boolean.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1801/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9ib29sZWFuLnRz) | `100.00% <100.00%> (ø)` | |
| [src/check/arbitrary/ObjectArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1801/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL2FyYml0cmFyeS9PYmplY3RBcmJpdHJhcnkudHM=) | `97.36% <100.00%> (ø)` | |
| [src/fast-check-default.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1801/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2Zhc3QtY2hlY2stZGVmYXVsdC50cw==) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1801?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1801?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Last update [25ded1d...80e9a83](https://codecov.io/gh/dubzzz/fast-check/pull/1801?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN).


Patch:
diff --git a/src/arbitrary/boolean.ts b/src/arbitrary/boolean.ts
new file mode 100644
index 00000000..82fedf49
--- /dev/null
+++ b/src/arbitrary/boolean.ts
@@ -0,0 +1,29 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { convertFromNext, convertToNext } from '../check/arbitrary/definition/Converters';
+import { integer } from './integer';
+
+/** @internal */
+function booleanMapper(v: number): boolean {
+  return v === 1;
+}
+
+/** @internal */
+function booleanUnmapper(v: unknown): number {
+  if (typeof v !== 'boolean') throw new Error('Unsupported input type');
+  return v === true ? 1 : 0;
+}
+
+/**
+ * For boolean values - `true` or `false`
+ * @remarks Since 0.0.6
+ * @public
+ */
+function boolean(): Arbitrary<boolean> {
+  return convertFromNext(
+    convertToNext(integer({ min: 0, max: 1 }))
+      .map(booleanMapper, booleanUnmapper)
+      .noBias()
+  );
+}
+
+export { boolean };
diff --git a/src/check/arbitrary/BooleanArbitrary.ts b/src/check/arbitrary/BooleanArbitrary.ts
deleted file mode 100644
index 6d394521..00000000
--- a/src/check/arbitrary/BooleanArbitrary.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Arbitrary } from './definition/Arbitrary';
-import { integer } from '../../arbitrary/integer';
-
-/**
- * For boolean values - `true` or `false`
- * @remarks Since 0.0.6
- * @public
- */
-function boolean(): Arbitrary<boolean> {
-  return integer(0, 1)
-    .map((v) => v === 1)
-    .noBias();
-}
-
-export { boolean };
diff --git a/src/check/arbitrary/ObjectArbitrary.ts b/src/check/arbitrary/ObjectArbitrary.ts
index aa12507f..b186e4cf 100644
--- a/src/check/arbitrary/ObjectArbitrary.ts
+++ b/src/check/arbitrary/ObjectArbitrary.ts
@@ -2,7 +2,7 @@ import { Arbitrary } from './definition/Arbitrary';
 
 import { stringify } from '../../utils/stringify';
 import { array } from '../../arbitrary/array';
-import { boolean } from './BooleanArbitrary';
+import { boolean } from '../../arbitrary/boolean';
 import { constant } from '../../arbitrary/constant';
 import { dictionary, toObject } from './DictionaryArbitrary';
 import { double } from './FloatingPointArbitrary';
diff --git a/src/fast-check-default.ts b/src/fast-check-default.ts
index 21c06e9b..ed657afd 100644
--- a/src/fast-check-default.ts
+++ b/src/fast-check-default.ts
@@ -24,7 +24,7 @@ import { bigInt, BigIntConstraints } from './arbitrary/bigInt';
 import { bigIntN } from './arbitrary/bigIntN';
 import { bigUint, BigUintConstraints } from './arbitrary/bigUint';
 import { bigUintN } from './arbitrary/bigUintN';
-import { boolean } from './check/arbitrary/BooleanArbitrary';
+import { boolean } from './arbitrary/boolean';
 import { falsy, FalsyContraints, FalsyValue } from './arbitrary/falsy';
 import { ascii } from './arbitrary/ascii';
 import { base64 } from './arbitrary/base64';


Test patch:
diff --git a/test/unit/arbitrary/boolean.spec.ts b/test/unit/arbitrary/boolean.spec.ts
new file mode 100644
index 00000000..f26b2f89
--- /dev/null
+++ b/test/unit/arbitrary/boolean.spec.ts
@@ -0,0 +1,66 @@
+import { boolean } from '../../../src/arbitrary/boolean';
+
+import { convertFromNextWithShrunkOnce, convertToNext } from '../../../src/check/arbitrary/definition/Converters';
+import { fakeNextArbitrary } from '../check/arbitrary/generic/NextArbitraryHelpers';
+
+import * as IntegerMock from '../../../src/arbitrary/integer';
+
+function beforeEachHook() {
+  jest.resetModules();
+  jest.restoreAllMocks();
+}
+beforeEach(beforeEachHook);
+
+describe('boolean', () => {
+  it('should only ask for two integer values without any bias', () => {
+    // Arrange
+    const { integer, unbiasedInstance } = prepare();
+
+    // Act
+    const arb = boolean();
+
+    // Assert
+    expect(convertToNext(arb)).toBe(unbiasedInstance);
+    expect(integer).toHaveBeenCalledTimes(1);
+    expect(integer).toHaveBeenCalledWith({ min: 0, max: 1 });
+  });
+
+  it('should produce true and false using the mapper', () => {
+    // Arrange
+    const { map } = prepare();
+
+    // Act
+    boolean();
+    const mapper = map.mock.calls[0][0];
+
+    // Assert
+    expect(mapper(0)).toBe(false);
+    expect(mapper(1)).toBe(true);
+  });
+
+  it('should produce 0 and 1 using the unmapper', () => {
+    // Arrange
+    const { map } = prepare();
+
+    // Act
+    boolean();
+    const unmapper = map.mock.calls[0][1]!;
+
+    // Assert
+    expect(unmapper(false)).toBe(0);
+    expect(unmapper(true)).toBe(1);
+  });
+});
+
+// Helpers
+
+function prepare() {
+  const { instance, map } = fakeNextArbitrary<number>();
+  const { instance: mappedInstance, noBias } = fakeNextArbitrary<boolean>();
+  const { instance: unbiasedInstance } = fakeNextArbitrary<boolean>();
+  const integer = jest.spyOn(IntegerMock, 'integer');
+  integer.mockImplementation(() => convertFromNextWithShrunkOnce(instance, undefined));
+  map.mockReturnValue(mappedInstance);
+  noBias.mockReturnValue(unbiasedInstance);
+  return { map, integer, unbiasedInstance };
+}
diff --git a/test/unit/check/arbitrary/BooleanArbitrary.spec.ts b/test/unit/check/arbitrary/BooleanArbitrary.spec.ts
deleted file mode 100644
index ed3276c1..00000000
--- a/test/unit/check/arbitrary/BooleanArbitrary.spec.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as fc from '../../../../lib/fast-check';
-
-import { boolean } from '../../../../src/check/arbitrary/BooleanArbitrary';
-
-import * as stubRng from '../../stubs/generators';
-
-describe('BooleanArbitrary', () => {
-  describe('boolean', () => {
-    it('Should produce true and false uniformaly', () =>
-      fc.assert(
-        fc.property(fc.integer(), (seed) => {
-          const mrng = stubRng.mutable.counter(seed);
-          const g1 = boolean().generate(mrng).value;
-          const g2 = boolean().generate(mrng).value;
-          return (g1 === true && g2 === false) || (g1 === false && g2 === true);
-        })
-      ));
-  });
-});