Repository: dubzzz/fast-check
Pull request #1743 (2021-04-14 20:04:51)

🚚 Move letrec 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: *moving code*

(✔️: yes, ❌: no)

## Potential impacts

No real impact expected


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/1743/builds/119795) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit cffa59cf63d4f2e7490dbee1f0f01086852f8d9c:

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

codecov[bot]: # [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1743?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) Report
> Merging [#1743](https://codecov.io/gh/dubzzz/fast-check/pull/1743?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (cffa59c) into [main](https://codecov.io/gh/dubzzz/fast-check/commit/57d5489fb625b3b9664bea7e28c0e31ea997e73d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (57d5489) will **decrease** coverage by `0.00%`.
> The diff coverage is `97.22%`.

[![Impacted file tree graph](https://codecov.io/gh/dubzzz/fast-check/pull/1743/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/1743?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    #1743      +/-   ##
==========================================
- Coverage   97.08%   97.07%   -0.01%     
==========================================
  Files         111      112       +1     
  Lines        3600     3590      -10     
  Branches      713      713              
==========================================
- Hits         3495     3485      -10     
  Misses        101      101              
  Partials        4        4              
```

| Flag | Coverage Δ | |
|---|---|---|
| unit-tests | `97.07% <97.22%> (-0.01%)` | :arrow_down: |
| unit-tests-10.x-Linux | `?` | |
| unit-tests-12.x-Linux | `97.07% <97.22%> (-0.01%)` | :arrow_down: |
| unit-tests-14.x-Linux | `?` | |

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/1743?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) | Coverage Δ | |
|---|---|---|
| [src/arbitrary/letrec.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1743/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9sZXRyZWMudHM=) | `94.44% <94.44%> (ø)` | |
| [src/arbitrary/\_internals/LazyArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1743/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9faW50ZXJuYWxzL0xhenlBcmJpdHJhcnkudHM=) | `100.00% <100.00%> (ø)` | |
| [src/fast-check-default.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1743/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%> (ø)` | |
| [src/check/arbitrary/MemoArbitrary.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1743/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL2FyYml0cmFyeS9NZW1vQXJiaXRyYXJ5LnRz) | `100.00% <0.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1743?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/1743?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Last update [57d5489...cffa59c](https://codecov.io/gh/dubzzz/fast-check/pull/1743?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/_internals/LazyArbitrary.ts b/src/arbitrary/_internals/LazyArbitrary.ts
new file mode 100644
index 00000000..b7d04436
--- /dev/null
+++ b/src/arbitrary/_internals/LazyArbitrary.ts
@@ -0,0 +1,30 @@
+import { NextArbitrary } from '../../check/arbitrary/definition/NextArbitrary';
+import { NextValue } from '../../check/arbitrary/definition/NextValue';
+import { Random } from '../../random/generator/Random';
+import { Stream } from '../../stream/Stream';
+
+/** @internal */
+export class LazyArbitrary<T> extends NextArbitrary<T> {
+  underlying: NextArbitrary<T> | null = null;
+  constructor(readonly name: string) {
+    super();
+  }
+  generate(mrng: Random, biasFactor: number | undefined): NextValue<T> {
+    if (!this.underlying) {
+      throw new Error(`Lazy arbitrary ${JSON.stringify(this.name)} not correctly initialized`);
+    }
+    return this.underlying.generate(mrng, biasFactor);
+  }
+  canGenerate(value: unknown): value is T {
+    if (!this.underlying) {
+      throw new Error(`Lazy arbitrary ${JSON.stringify(this.name)} not correctly initialized`);
+    }
+    return this.underlying.canGenerate(value);
+  }
+  shrink(value: T, context?: unknown): Stream<NextValue<T>> {
+    if (!this.underlying) {
+      throw new Error(`Lazy arbitrary ${JSON.stringify(this.name)} not correctly initialized`);
+    }
+    return this.underlying.shrink(value, context);
+  }
+}
diff --git a/src/arbitrary/letrec.ts b/src/arbitrary/letrec.ts
new file mode 100644
index 00000000..592b3246
--- /dev/null
+++ b/src/arbitrary/letrec.ts
@@ -0,0 +1,48 @@
+import { LazyArbitrary } from './_internals/LazyArbitrary';
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { convertFromNext, convertToNext } from '../check/arbitrary/definition/Converters';
+
+/**
+ * For mutually recursive types
+ *
+ * @example
+ * ```typescript
+ * const { tree } = fc.letrec(tie => ({
+ *   tree: fc.oneof({depthFactor: 0.5}, tie('leaf'), tie('node')),
+ *   node: fc.tuple(tie('tree'), tie('tree')),
+ *   leaf: fc.nat()
+ * }));
+ * // tree is 50% of node, 50% of leaf
+ * // the ratio goes in favor of leaves as we go deeper in the tree (thanks to depthFactor)
+ * ```
+ *
+ * @param builder - Arbitraries builder based on themselves (through `tie`)
+ *
+ * @remarks Since 1.16.0
+ * @public
+ */
+export function letrec<T>(
+  builder: (tie: (key: string) => Arbitrary<unknown>) => { [K in keyof T]: Arbitrary<T[K]> }
+): { [K in keyof T]: Arbitrary<T[K]> } {
+  const lazyArbs: { [K in keyof T]?: LazyArbitrary<unknown> } = Object.create(null);
+  const tie = (key: keyof T): Arbitrary<any> => {
+    if (!Object.prototype.hasOwnProperty.call(lazyArbs, key)) {
+      // Call to hasOwnProperty ensures that the property key will be defined
+      lazyArbs[key] = new LazyArbitrary(String(key));
+    }
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    return convertFromNext(lazyArbs[key]!);
+  };
+  const strictArbs = builder(tie as any);
+  for (const key in strictArbs) {
+    if (!Object.prototype.hasOwnProperty.call(strictArbs, key)) {
+      // Prevents accidental iteration over properties inherited from an object’s prototype
+      continue;
+    }
+    const lazyAtKey: LazyArbitrary<unknown> | undefined = lazyArbs[key];
+    const lazyArb = lazyAtKey !== undefined ? lazyAtKey : new LazyArbitrary(key);
+    lazyArb.underlying = convertToNext(strictArbs[key]);
+    lazyArbs[key] = lazyArb;
+  }
+  return strictArbs;
+}
diff --git a/src/check/arbitrary/LetRecArbitrary.ts b/src/check/arbitrary/LetRecArbitrary.ts
deleted file mode 100644
index 3143625a..00000000
--- a/src/check/arbitrary/LetRecArbitrary.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import { Stream } from '../../fast-check-default';
-import { Random } from '../../random/generator/Random';
-import { Arbitrary } from './definition/Arbitrary';
-import { convertFromNext, convertToNext } from './definition/Converters';
-import { NextArbitrary } from './definition/NextArbitrary';
-import { NextValue } from './definition/NextValue';
-
-/** @internal */
-export class LazyArbitrary extends NextArbitrary<any> {
-  underlying: NextArbitrary<any> | null = null;
-  constructor(readonly name: string) {
-    super();
-  }
-  generate(mrng: Random, biasFactor: number | undefined): NextValue<any> {
-    if (!this.underlying) {
-      throw new Error(`Lazy arbitrary ${JSON.stringify(this.name)} not correctly initialized`);
-    }
-    return this.underlying.generate(mrng, biasFactor);
-  }
-  canGenerate(value: unknown): value is any {
-    if (!this.underlying) {
-      throw new Error(`Lazy arbitrary ${JSON.stringify(this.name)} not correctly initialized`);
-    }
-    return this.underlying.canGenerate(value);
-  }
-  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-  shrink(value: any, context?: unknown): Stream<NextValue<any>> {
-    if (!this.underlying) {
-      throw new Error(`Lazy arbitrary ${JSON.stringify(this.name)} not correctly initialized`);
-    }
-    return this.underlying.shrink(value, context);
-  }
-}
-
-/**
- * For mutually recursive types
- *
- * @example
- * ```typescript
- * const { tree } = fc.letrec(tie => ({
- *   tree: fc.oneof({depthFactor: 0.5}, tie('leaf'), tie('node')),
- *   node: fc.tuple(tie('tree'), tie('tree')),
- *   leaf: fc.nat()
- * }));
- * // tree is 50% of node, 50% of leaf
- * // the ratio goes in favor of leaves as we go deeper in the tree (thanks to depthFactor)
- * ```
- *
- * @param builder - Arbitraries builder based on themselves (through `tie`)
- *
- * @remarks Since 1.16.0
- * @public
- */
-export function letrec<T>(
-  builder: (tie: (key: string) => Arbitrary<unknown>) => { [K in keyof T]: Arbitrary<T[K]> }
-): { [K in keyof T]: Arbitrary<T[K]> } {
-  const lazyArbs: { [K in keyof T]?: LazyArbitrary } = Object.create(null);
-  const tie = (key: keyof T): Arbitrary<any> => {
-    if (!Object.prototype.hasOwnProperty.call(lazyArbs, key)) {
-      // Call to hasOwnProperty ensures that the property key will be defined
-      lazyArbs[key] = new LazyArbitrary(key as any);
-    }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return convertFromNext(lazyArbs[key]!);
-  };
-  const strictArbs = builder(tie as any);
-  for (const key in strictArbs) {
-    if (!Object.prototype.hasOwnProperty.call(strictArbs, key)) {
-      // Prevents accidental iteration over properties inherited from an object’s prototype
-      continue;
-    }
-    const lazyAtKey: LazyArbitrary | undefined = lazyArbs[key];
-    const lazyArb = lazyAtKey !== undefined ? lazyAtKey : new LazyArbitrary(key);
-    lazyArb.underlying = convertToNext(strictArbs[key]);
-    lazyArbs[key] = lazyArb;
-  }
-  return strictArbs;
-}
diff --git a/src/fast-check-default.ts b/src/fast-check-default.ts
index fde67995..c5f2226a 100644
--- a/src/fast-check-default.ts
+++ b/src/fast-check-default.ts
@@ -45,7 +45,7 @@ import { maxSafeInteger } from './arbitrary/maxSafeInteger';
 import { maxSafeNat } from './arbitrary/maxSafeNat';
 import { nat, NatConstraints } from './arbitrary/nat';
 import { ipV4, ipV4Extended, ipV6 } from './check/arbitrary/IpArbitrary';
-import { letrec } from './check/arbitrary/LetRecArbitrary';
+import { letrec } from './arbitrary/letrec';
 import { lorem, LoremConstraints } from './check/arbitrary/LoremArbitrary';
 import { mapToConstant } from './check/arbitrary/MapToConstantArbitrary';
 import { memo, Memo } from './check/arbitrary/MemoArbitrary';


Test patch:
diff --git a/test/unit/check/arbitrary/LetRecArbitrary.itest.spec.ts b/test/unit/arbitrary/LetRecArbitrary.itest.spec.ts
similarity index 83%
rename from test/unit/check/arbitrary/LetRecArbitrary.itest.spec.ts
rename to test/unit/arbitrary/LetRecArbitrary.itest.spec.ts
index 3365ddb6..70335e70 100644
--- a/test/unit/check/arbitrary/LetRecArbitrary.itest.spec.ts
+++ b/test/unit/arbitrary/LetRecArbitrary.itest.spec.ts
@@ -1,16 +1,16 @@
-import { letrec as letrecOld } from '../../../../src/check/arbitrary/LetRecArbitrary';
-import { NextArbitrary } from '../../../../src/check/arbitrary/definition/NextArbitrary';
-import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';
+import { letrec as letrecOld } from '../../../src/arbitrary/letrec';
+import { NextArbitrary } from '../../../src/check/arbitrary/definition/NextArbitrary';
+import { Arbitrary } from '../../../src/check/arbitrary/definition/Arbitrary';
 
-import { convertFromNext, convertToNext } from '../../../../src/check/arbitrary/definition/Converters';
-import { FakeIntegerArbitrary } from './generic/NextArbitraryHelpers';
+import { convertFromNext, convertToNext } from '../../../src/check/arbitrary/definition/Converters';
+import { FakeIntegerArbitrary } from '../check/arbitrary/generic/NextArbitraryHelpers';
 import {
   assertGenerateEquivalentTo,
   assertGenerateProducesSameValueGivenSameSeed,
   assertGenerateProducesValuesFlaggedAsCanGenerate,
   assertShrinkProducesSameValueWithoutInitialContext,
   assertShrinkProducesValuesFlaggedAsCanGenerate,
-} from './generic/NextArbitraryAssertions';
+} from '../check/arbitrary/generic/NextArbitraryAssertions';
 
 // Temporary rewrapping around letrec
 // Should be removed with next major (no more Arbitrary, only NextArbitrary)
diff --git a/test/unit/check/arbitrary/LetRecArbitrary.utest.spec.ts b/test/unit/arbitrary/LetRecArbitrary.utest.spec.ts
similarity index 91%
rename from test/unit/check/arbitrary/LetRecArbitrary.utest.spec.ts
rename to test/unit/arbitrary/LetRecArbitrary.utest.spec.ts
index d897812b..6d1d180b 100644
--- a/test/unit/check/arbitrary/LetRecArbitrary.utest.spec.ts
+++ b/test/unit/arbitrary/LetRecArbitrary.utest.spec.ts
@@ -1,12 +1,13 @@
-import { LazyArbitrary, letrec as letrecOld } from '../../../../src/check/arbitrary/LetRecArbitrary';
-import { NextArbitrary } from '../../../../src/check/arbitrary/definition/NextArbitrary';
-import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
-import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';
+import { letrec as letrecOld } from '../../../src/arbitrary/letrec';
+import { LazyArbitrary } from '../../../src/arbitrary/_internals/LazyArbitrary';
+import { NextArbitrary } from '../../../src/check/arbitrary/definition/NextArbitrary';
+import { NextValue } from '../../../src/check/arbitrary/definition/NextValue';
+import { Arbitrary } from '../../../src/check/arbitrary/definition/Arbitrary';
 
-import * as stubRng from '../../stubs/generators';
-import { convertFromNext, convertToNext } from '../../../../src/check/arbitrary/definition/Converters';
-import { fakeNextArbitrary } from './generic/NextArbitraryHelpers';
-import { Stream } from '../../../../src/stream/Stream';
+import * as stubRng from '../stubs/generators';
+import { convertFromNext, convertToNext } from '../../../src/check/arbitrary/definition/Converters';
+import { Stream } from '../../../src/stream/Stream';
+import { fakeNextArbitrary } from '../check/arbitrary/generic/NextArbitraryHelpers';
 
 const mrngNoCall = stubRng.mutable.nocall();
 
@@ -114,8 +115,8 @@ describe('letrec', () => {
       expect(arb1).toBeInstanceOf(LazyArbitrary);
       expect(arb2).toBeInstanceOf(LazyArbitrary);
       expect(arb3).not.toBeInstanceOf(LazyArbitrary);
-      expect(((arb1 as any) as LazyArbitrary).underlying).toBe(arb2);
-      expect(((arb2 as any) as LazyArbitrary).underlying).toBe(arb3);
+      expect(((arb1 as any) as LazyArbitrary<unknown>).underlying).toBe(arb2);
+      expect(((arb2 as any) as LazyArbitrary<unknown>).underlying).toBe(arb3);
       expect(arb3).toBe(expectedArb);
     });
 
@@ -137,8 +138,8 @@ describe('letrec', () => {
       expect(arb1).toBeInstanceOf(LazyArbitrary);
       expect(arb2).toBeInstanceOf(LazyArbitrary);
       expect(arb3).not.toBeInstanceOf(LazyArbitrary);
-      expect(((arb1 as any) as LazyArbitrary).underlying).toBe(arb2);
-      expect(((arb2 as any) as LazyArbitrary).underlying).toBe(arb3);
+      expect(((arb1 as any) as LazyArbitrary<unknown>).underlying).toBe(arb2);
+      expect(((arb2 as any) as LazyArbitrary<unknown>).underlying).toBe(arb3);
       expect(arb3).toBe(expectedArb);
     });
   });