Repository: dubzzz/fast-check
Pull request #1760 (2021-04-17 17:45:47)

⚰️ Remove duplicated tests for `letrec`
<!-- 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: *removing dead code*

(✔️: 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/1760/builds/120838) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit dd9524fba891b7dd3022d541ef3a848fcb1d6220:

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

codecov[bot]: # [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1760?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) Report
> :exclamation: No coverage uploaded for pull request base (`main@5539881`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#section-missing-base-commit).
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/dubzzz/fast-check/pull/1760/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/1760?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    #1760   +/-   ##
=======================================
  Coverage        ?   96.90%           
=======================================
  Files           ?      115           
  Lines           ?     3620           
  Branches        ?      715           
=======================================
  Hits            ?     3508           
  Misses          ?      108           
  Partials        ?        4           
```

| Flag | Coverage Δ | |
|---|---|---|
| unit-tests | `96.90% <ø> (?)` | |
| unit-tests-14.x-Linux | `96.90% <ø> (?)` | |

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.


------

[Continue to review full report at Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1760?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/1760?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Last update [5539881...dd9524f](https://codecov.io/gh/dubzzz/fast-check/pull/1760?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/check/arbitrary/CloneArbitrary.ts b/src/arbitrary/_internals/CloneArbitrary.ts
similarity index 70%
rename from src/check/arbitrary/CloneArbitrary.ts
rename to src/arbitrary/_internals/CloneArbitrary.ts
index 03a90c65..d07a97ad 100644
--- a/src/check/arbitrary/CloneArbitrary.ts
+++ b/src/arbitrary/_internals/CloneArbitrary.ts
@@ -1,13 +1,11 @@
+import { NextArbitrary } from '../../check/arbitrary/definition/NextArbitrary';
+import { NextValue } from '../../check/arbitrary/definition/NextValue';
+import { cloneMethod } from '../../check/symbols';
 import { Random } from '../../random/generator/Random';
 import { Stream } from '../../stream/Stream';
-import { cloneMethod } from '../symbols';
-import { Arbitrary } from './definition/Arbitrary';
-import { convertFromNext, convertToNext } from './definition/Converters';
-import { NextArbitrary } from './definition/NextArbitrary';
-import { NextValue } from './definition/NextValue';
 
 /** @internal */
-class CloneArbitrary<T> extends NextArbitrary<T[]> {
+export class CloneArbitrary<T> extends NextArbitrary<T[]> {
   constructor(readonly arb: NextArbitrary<T>, readonly numValues: number) {
     super();
   }
@@ -86,35 +84,3 @@ class CloneArbitrary<T> extends NextArbitrary<T[]> {
     return new NextValue(vs, contexts);
   }
 }
-
-/**
- * Type of the value produced by {@link clone}
- * @remarks Since 2.5.0
- * @public
- */
-export type CloneValue<T, N extends number> = N extends 0
-  ? []
-  : N extends 1
-  ? [T]
-  : N extends 2
-  ? [T, T]
-  : N extends 3
-  ? [T, T, T]
-  : N extends 4
-  ? [T, T, T, T]
-  : T[];
-
-/**
- * Clone the values generated by `arb` in order to produce fully equal values (might not be equal in terms of === or ==)
- *
- * @param arb - Source arbitrary
- * @param numValues - Number of values to produce
- *
- * @remarks Since 2.5.0
- * @public
- */
-function clone<T, N extends number>(arb: Arbitrary<T>, numValues: N): Arbitrary<CloneValue<T, N>>;
-function clone<T>(arb: Arbitrary<T>, numValues: number): Arbitrary<T[]> {
-  return convertFromNext(new CloneArbitrary(convertToNext(arb), numValues));
-}
-export { clone };
diff --git a/src/check/arbitrary/StreamArbitrary.ts b/src/arbitrary/_internals/StreamArbitrary.ts
similarity index 66%
rename from src/check/arbitrary/StreamArbitrary.ts
rename to src/arbitrary/_internals/StreamArbitrary.ts
index bd8fead3..2d7e296c 100644
--- a/src/check/arbitrary/StreamArbitrary.ts
+++ b/src/arbitrary/_internals/StreamArbitrary.ts
@@ -1,14 +1,12 @@
+import { NextArbitrary } from '../../check/arbitrary/definition/NextArbitrary';
+import { NextValue } from '../../check/arbitrary/definition/NextValue';
+import { cloneMethod } from '../../check/symbols';
 import { Random } from '../../random/generator/Random';
 import { Stream } from '../../stream/Stream';
 import { stringify } from '../../utils/stringify';
-import { cloneMethod } from '../symbols';
-import { Arbitrary } from './definition/Arbitrary';
-import { convertFromNext, convertToNext } from './definition/Converters';
-import { NextArbitrary } from './definition/NextArbitrary';
-import { NextValue } from './definition/NextValue';
 
 /** @internal */
-class StreamArbitrary<T> extends NextArbitrary<Stream<T>> {
+export class StreamArbitrary<T> extends NextArbitrary<Stream<T>> {
   constructor(readonly arb: NextArbitrary<T>) {
     super();
   }
@@ -42,19 +40,3 @@ class StreamArbitrary<T> extends NextArbitrary<Stream<T>> {
     return Stream.nil();
   }
 }
-
-/**
- * Produce an infinite stream of values
- *
- * WARNING: Requires Object.assign
- *
- * @param arb - Arbitrary used to generate the values
- *
- * @remarks Since 1.8.0
- * @public
- */
-function infiniteStream<T>(arb: Arbitrary<T>): Arbitrary<Stream<T>> {
-  return convertFromNext(new StreamArbitrary(convertToNext(arb)));
-}
-
-export { infiniteStream };
diff --git a/src/arbitrary/clone.ts b/src/arbitrary/clone.ts
new file mode 100644
index 00000000..a423aae7
--- /dev/null
+++ b/src/arbitrary/clone.ts
@@ -0,0 +1,35 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { convertFromNext, convertToNext } from '../check/arbitrary/definition/Converters';
+import { CloneArbitrary } from './_internals/CloneArbitrary';
+
+/**
+ * Type of the value produced by {@link clone}
+ * @remarks Since 2.5.0
+ * @public
+ */
+export type CloneValue<T, N extends number> = N extends 0
+  ? []
+  : N extends 1
+  ? [T]
+  : N extends 2
+  ? [T, T]
+  : N extends 3
+  ? [T, T, T]
+  : N extends 4
+  ? [T, T, T, T]
+  : T[];
+
+/**
+ * Clone the values generated by `arb` in order to produce fully equal values (might not be equal in terms of === or ==)
+ *
+ * @param arb - Source arbitrary
+ * @param numValues - Number of values to produce
+ *
+ * @remarks Since 2.5.0
+ * @public
+ */
+function clone<T, N extends number>(arb: Arbitrary<T>, numValues: N): Arbitrary<CloneValue<T, N>>;
+function clone<T>(arb: Arbitrary<T>, numValues: number): Arbitrary<T[]> {
+  return convertFromNext(new CloneArbitrary(convertToNext(arb), numValues));
+}
+export { clone };
diff --git a/src/check/arbitrary/DedupArbitrary.ts b/src/arbitrary/dedup.ts
similarity index 83%
rename from src/check/arbitrary/DedupArbitrary.ts
rename to src/arbitrary/dedup.ts
index 5f76836d..71e60c4d 100644
--- a/src/check/arbitrary/DedupArbitrary.ts
+++ b/src/arbitrary/dedup.ts
@@ -1,4 +1,4 @@
-import { clone, CloneValue } from './CloneArbitrary';
+import { clone, CloneValue } from './clone';
 
 /**
  * @deprecated Switch to {@link CloneValue} instead
diff --git a/src/check/arbitrary/AsyncSchedulerArbitrary.ts b/src/check/arbitrary/AsyncSchedulerArbitrary.ts
index 9b223d26..08fde94c 100644
--- a/src/check/arbitrary/AsyncSchedulerArbitrary.ts
+++ b/src/check/arbitrary/AsyncSchedulerArbitrary.ts
@@ -1,9 +1,12 @@
 import { cloneMethod } from '../symbols';
 import { Random } from '../../random/generator/Random';
 import { Arbitrary } from './definition/Arbitrary';
-import { Shrinkable } from './definition/Shrinkable';
 import { stringify } from '../../utils/stringify';
 import { escapeForTemplateString } from './helpers/TextEscaper';
+import { NextArbitrary } from './definition/NextArbitrary';
+import { convertFromNext } from './definition/Converters';
+import { Stream } from '../../fast-check-default';
+import { NextValue } from './definition/NextValue';
 
 /**
  * Define an item to be passed to `scheduleSequence`
@@ -391,12 +394,12 @@ class SchedulerImplem<TMetaData> implements Scheduler<TMetaData> {
 }
 
 /** @internal */
-class SchedulerArbitrary<TMetaData> extends Arbitrary<Scheduler<TMetaData>> {
+class SchedulerArbitrary<TMetaData> extends NextArbitrary<Scheduler<TMetaData>> {
   constructor(readonly act: (f: () => Promise<void>) => Promise<unknown>) {
     super();
   }
 
-  generate(mrng: Random) {
+  generate(mrng: Random, _biasFactor: number | undefined): NextValue<Scheduler<TMetaData>> {
     const buildNextTaskIndex = (r: Random) => {
       return {
         clone: () => buildNextTaskIndex(r.clone()),
@@ -405,7 +408,17 @@ class SchedulerArbitrary<TMetaData> extends Arbitrary<Scheduler<TMetaData>> {
         },
       };
     };
-    return new Shrinkable(new SchedulerImplem<TMetaData>(this.act, buildNextTaskIndex(mrng.clone())));
+    return new NextValue(new SchedulerImplem<TMetaData>(this.act, buildNextTaskIndex(mrng.clone())));
+  }
+
+  canGenerate(value: unknown): value is Scheduler<TMetaData> {
+    // Not supported yet
+    return false;
+  }
+
+  shrink(_value: Scheduler<TMetaData>, _context?: unknown): Stream<NextValue<Scheduler<TMetaData>>> {
+    // Not supported yet
+    return Stream.nil();
   }
 }
 
@@ -416,7 +429,7 @@ class SchedulerArbitrary<TMetaData> extends Arbitrary<Scheduler<TMetaData>> {
  */
 function scheduler<TMetaData = unknown>(constraints?: SchedulerConstraints): Arbitrary<Scheduler<TMetaData>> {
   const { act = (f: () => Promise<void>) => f() } = constraints || {};
-  return new SchedulerArbitrary<TMetaData>(act);
+  return convertFromNext(new SchedulerArbitrary<TMetaData>(act));
 }
 
 /**
diff --git a/src/fast-check-default.ts b/src/fast-check-default.ts
index 48c40f0e..dfefbfaf 100644
--- a/src/fast-check-default.ts
+++ b/src/fast-check-default.ts
@@ -32,8 +32,8 @@ import { constant } from './arbitrary/constant';
 import { constantFrom } from './arbitrary/constantFrom';
 import { context, ContextValue } from './arbitrary/context';
 import { date } from './check/arbitrary/DateArbitrary';
-import { clone, CloneValue } from './check/arbitrary/CloneArbitrary';
-import { dedup, DedupValue } from './check/arbitrary/DedupArbitrary';
+import { clone, CloneValue } from './arbitrary/clone';
+import { dedup, DedupValue } from './arbitrary/dedup';
 import { Arbitrary } from './check/arbitrary/definition/Arbitrary';
 import { Shrinkable } from './check/arbitrary/definition/Shrinkable';
 import { dictionary } from './check/arbitrary/DictionaryArbitrary';
@@ -66,7 +66,7 @@ import { oneof, OneOfValue, OneOfConstraints } from './arbitrary/oneof';
 import { option, OptionConstraints } from './arbitrary/option';
 import { record, RecordConstraints, RecordValue } from './check/arbitrary/RecordArbitrary';
 import { set, SetConstraints } from './arbitrary/set';
-import { infiniteStream } from './check/arbitrary/StreamArbitrary';
+import { infiniteStream } from './arbitrary/infiniteStream';
 import {
   asciiString,
   base64String,


Test patch:
diff --git a/src/arbitrary/infiniteStream.ts b/src/arbitrary/infiniteStream.ts
new file mode 100644
index 00000000..2fa4d2a2
--- /dev/null
+++ b/src/arbitrary/infiniteStream.ts
@@ -0,0 +1,20 @@
+import { Stream } from '../stream/Stream';
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { convertFromNext, convertToNext } from '../check/arbitrary/definition/Converters';
+import { StreamArbitrary } from './_internals/StreamArbitrary';
+
+/**
+ * Produce an infinite stream of values
+ *
+ * WARNING: Requires Object.assign
+ *
+ * @param arb - Arbitrary used to generate the values
+ *
+ * @remarks Since 1.8.0
+ * @public
+ */
+function infiniteStream<T>(arb: Arbitrary<T>): Arbitrary<Stream<T>> {
+  return convertFromNext(new StreamArbitrary(convertToNext(arb)));
+}
+
+export { infiniteStream };
diff --git a/test/unit/check/arbitrary/CloneArbitrary.spec.ts b/test/unit/arbitrary/CloneArbitrary.spec.ts
similarity index 77%
rename from test/unit/check/arbitrary/CloneArbitrary.spec.ts
rename to test/unit/arbitrary/CloneArbitrary.spec.ts
index a1c08070..8112b6fb 100644
--- a/test/unit/check/arbitrary/CloneArbitrary.spec.ts
+++ b/test/unit/arbitrary/CloneArbitrary.spec.ts
@@ -1,16 +1,16 @@
-import * as fc from '../../../../lib/fast-check';
+import * as fc from '../../../lib/fast-check';
 
-import { clone } from '../../../../src/check/arbitrary/CloneArbitrary';
-import { nat } from '../../../../src/arbitrary/nat';
+import { clone } from '../../../src/arbitrary/clone';
+import { nat } from '../../../src/arbitrary/nat';
 
-import * as genericHelper from './generic/GenericArbitraryHelper';
+import * as genericHelper from '../check/arbitrary/generic/GenericArbitraryHelper';
 
-import * as stubRng from '../../stubs/generators';
-import { hasCloneMethod } from '../../../../src/check/symbols';
-import { context } from '../../../../src/arbitrary/context';
-import { cloneMethod } from '../../../../lib/fast-check';
-import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';
-import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
+import * as stubRng from '../stubs/generators';
+import { hasCloneMethod } from '../../../src/check/symbols';
+import { context } from '../../../src/arbitrary/context';
+import { cloneMethod } from '../../../lib/fast-check';
+import { Arbitrary } from '../../../src/check/arbitrary/definition/Arbitrary';
+import { Shrinkable } from '../../../src/check/arbitrary/definition/Shrinkable';
 
 export const isStrictlySmaller = (arr1: number[], arr2: number[]): boolean => {
   for (let idx = 0; idx !== arr1.length; ++idx) {
diff --git a/test/unit/arbitrary/LetRecArbitrary.itest.spec.ts b/test/unit/arbitrary/LetRecArbitrary.itest.spec.ts
deleted file mode 100644
index 70335e70..00000000
--- a/test/unit/arbitrary/LetRecArbitrary.itest.spec.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-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 '../check/arbitrary/generic/NextArbitraryHelpers';
-import {
-  assertGenerateEquivalentTo,
-  assertGenerateProducesSameValueGivenSameSeed,
-  assertGenerateProducesValuesFlaggedAsCanGenerate,
-  assertShrinkProducesSameValueWithoutInitialContext,
-  assertShrinkProducesValuesFlaggedAsCanGenerate,
-} from '../check/arbitrary/generic/NextArbitraryAssertions';
-
-// Temporary rewrapping around letrec
-// Should be removed with next major (no more Arbitrary, only NextArbitrary)
-export function letrec<T>(
-  builder: (tie: (key: string) => NextArbitrary<unknown>) => { [K in keyof T]: NextArbitrary<T[K]> }
-): { [K in keyof T]: NextArbitrary<T[K]> } {
-  const outOld = letrecOld((tieOld) => {
-    const tie: (key: string) => NextArbitrary<unknown> = (key) => convertToNext(tieOld(key));
-    const built = builder(tie);
-    const revampedBuilt: { [K in keyof T]: Arbitrary<T[K]> } = Object.create(null);
-    for (const k of Object.keys(built)) {
-      revampedBuilt[k as keyof T] = convertFromNext(built[k as keyof T]);
-    }
-    return revampedBuilt;
-  });
-  const out: { [K in keyof T]: NextArbitrary<T[K]> } = Object.create(null);
-  for (const k of Object.keys(outOld)) {
-    out[k as keyof T] = convertToNext(outOld[k as keyof T]);
-  }
-  return out;
-}
-
-describe('letrec', () => {
-  const letrecBuilder = () => {
-    const { a } = letrec((tie) => ({
-      a: tie('b'),
-      b: tie('c'),
-      c: new FakeIntegerArbitrary(),
-    }));
-    return a;
-  };
-
-  it('should generate the values as-if we directly called the target arbitrary', () => {
-    assertGenerateEquivalentTo(letrecBuilder, () => new FakeIntegerArbitrary(), {
-      isEqualContext: (c1, c2) => {
-        expect(c2).toEqual(c1);
-      },
-    });
-  });
-
-  it('should generate the same values given the same seed', () => {
-    assertGenerateProducesSameValueGivenSameSeed(letrecBuilder);
-  });
-
-  it('should recognize values that would have been generated using it during generate', () => {
-    assertGenerateProducesValuesFlaggedAsCanGenerate(letrecBuilder);
-  });
-
-  it('should shrink towards the same values given the same seed', () => {
-    assertGenerateProducesSameValueGivenSameSeed(letrecBuilder);
-  });
-
-  it('should be able to shrink without any context if underlyings do', () => {
-    assertShrinkProducesSameValueWithoutInitialContext(letrecBuilder);
-  });
-
-  it('should recognize values that would have been generated using it during shrink', () => {
-    assertShrinkProducesValuesFlaggedAsCanGenerate(letrecBuilder);
-  });
-});
diff --git a/test/unit/arbitrary/LetRecArbitrary.utest.spec.ts b/test/unit/arbitrary/LetRecArbitrary.utest.spec.ts
deleted file mode 100644
index 6d1d180b..00000000
--- a/test/unit/arbitrary/LetRecArbitrary.utest.spec.ts
+++ /dev/null
@@ -1,364 +0,0 @@
-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 { Stream } from '../../../src/stream/Stream';
-import { fakeNextArbitrary } from '../check/arbitrary/generic/NextArbitraryHelpers';
-
-const mrngNoCall = stubRng.mutable.nocall();
-
-// Temporary rewrapping around letrec
-// Should be removed with next major (no more Arbitrary, only NextArbitrary)
-export function letrec<T>(
-  builder: (tie: (key: string) => NextArbitrary<unknown>) => { [K in keyof T]: NextArbitrary<T[K]> }
-): { [K in keyof T]: NextArbitrary<T[K]> } {
-  const outOld = letrecOld((tieOld) => {
-    const tie: (key: string) => NextArbitrary<unknown> = (key) => convertToNext(tieOld(key));
-    const built = builder(tie);
-    const revampedBuilt: { [K in keyof T]: Arbitrary<T[K]> } = Object.create(null);
-    for (const k of Object.keys(built)) {
-      revampedBuilt[k as keyof T] = convertFromNext(built[k as keyof T]);
-    }
-    return revampedBuilt;
-  });
-  const out: { [K in keyof T]: NextArbitrary<T[K]> } = Object.create(null);
-  for (const k of Object.keys(outOld)) {
-    out[k as keyof T] = convertToNext(outOld[k as keyof T]);
-  }
-  return out;
-}
-
-describe('letrec', () => {
-  describe('builder', () => {
-    it('should be able to construct independant arbitraries', () => {
-      // Arrange
-      const { instance: expectedArb1 } = fakeNextArbitrary();
-      const { instance: expectedArb2 } = fakeNextArbitrary();
-
-      // Act
-      const { arb1, arb2 } = letrec((_tie) => ({
-        arb1: expectedArb1,
-        arb2: expectedArb2,
-      }));
-
-      // Assert
-      expect(arb1).toBe(expectedArb1);
-      expect(arb2).toBe(expectedArb2);
-    });
-
-    it('should not produce LazyArbitrary for no-tie constructs', () => {
-      // Arrange
-      const { instance: expectedArb } = fakeNextArbitrary();
-
-      // Act
-      const { arb } = letrec((_tie) => ({
-        arb: expectedArb,
-      }));
-
-      // Assert
-      expect(arb).not.toBeInstanceOf(LazyArbitrary);
-    });
-
-    it('should not produce LazyArbitrary for indirect tie constructs', () => {
-      // Arrange / Act
-      const { arb } = letrec((tie) => {
-        const { instance: expectedArb, generate } = fakeNextArbitrary();
-        generate.mockImplementation((...args) => tie('arb').generate(...args));
-        return {
-          // arb is an arbitrary wrapping the tie value (as fc.array)
-          arb: expectedArb,
-        };
-      });
-
-      // Assert
-      expect(arb).not.toBeInstanceOf(LazyArbitrary);
-    });
-
-    it('should produce LazyArbitrary for direct tie constructs', () => {
-      // Arrange / Act
-      const { arb } = letrec((tie) => ({
-        arb: tie('arb'),
-      }));
-
-      // Assert
-      expect(arb).toBeInstanceOf(LazyArbitrary);
-    });
-
-    it('should be able to construct mutually recursive arbitraries', () => {
-      // Arrange / Act
-      const { arb1, arb2 } = letrec((tie) => ({
-        arb1: tie('arb2'),
-        arb2: tie('arb1'),
-      }));
-
-      // Assert
-      expect(arb1).toBeDefined();
-      expect(arb2).toBeDefined();
-    });
-
-    it('should apply tie correctly', () => {
-      // Arrange
-      const { instance: expectedArb } = fakeNextArbitrary();
-
-      // Act
-      const { arb1, arb2, arb3 } = letrec((tie) => ({
-        arb1: tie('arb2'),
-        arb2: tie('arb3'),
-        arb3: expectedArb,
-      }));
-
-      // Assert
-      expect(arb1).toBeInstanceOf(LazyArbitrary);
-      expect(arb2).toBeInstanceOf(LazyArbitrary);
-      expect(arb3).not.toBeInstanceOf(LazyArbitrary);
-      expect(((arb1 as any) as LazyArbitrary<unknown>).underlying).toBe(arb2);
-      expect(((arb2 as any) as LazyArbitrary<unknown>).underlying).toBe(arb3);
-      expect(arb3).toBe(expectedArb);
-    });
-
-    it('should apply tie the same way for a reversed declaration', () => {
-      // Arrange
-      const { instance: expectedArb } = fakeNextArbitrary();
-
-      // Act
-      const { arb1, arb2, arb3 } = letrec((tie) => ({
-        // Same scenario as 'should apply tie correctly'
-        // except we declared arb3 > arb2 > arb1
-        // instead of arb1 > arb2 > arb3
-        arb3: expectedArb,
-        arb2: tie('arb3'),
-        arb1: tie('arb2'),
-      }));
-
-      // Assert
-      expect(arb1).toBeInstanceOf(LazyArbitrary);
-      expect(arb2).toBeInstanceOf(LazyArbitrary);
-      expect(arb3).not.toBeInstanceOf(LazyArbitrary);
-      expect(((arb1 as any) as LazyArbitrary<unknown>).underlying).toBe(arb2);
-      expect(((arb2 as any) as LazyArbitrary<unknown>).underlying).toBe(arb3);
-      expect(arb3).toBe(expectedArb);
-    });
-  });
-
-  describe('generate', () => {
-    it('should be able to delay calls to tie to generate', () => {
-      // Arrange
-      const biasFactor = 69;
-      const { instance: simpleArb, generate } = fakeNextArbitrary();
-      generate.mockReturnValueOnce(new NextValue(null));
-
-      // Act
-      const { arb1 } = letrec((tie) => {
-        const { instance: simpleArb2, generate: generate2 } = fakeNextArbitrary();
-        generate2.mockImplementation((...args) => tie('arb2').generate(...args));
-        return {
-          arb1: simpleArb2,
-          arb2: simpleArb,
-        };
-      });
-      expect(generate).not.toHaveBeenCalled();
-      arb1.generate(mrngNoCall, biasFactor);
-
-      // Assert
-      expect(generate).toHaveBeenCalledTimes(1);
-      expect(generate).toHaveBeenCalledWith(mrngNoCall, biasFactor);
-    });
-
-    it('should throw on generate if tie receives an invalid parameter', () => {
-      // Arrange
-      const biasFactor = 42;
-      const { arb1 } = letrec((tie) => ({
-        arb1: tie('missing'),
-      }));
-
-      // Act / Assert
-      expect(() => arb1.generate(mrngNoCall, biasFactor)).toThrowErrorMatchingInlineSnapshot(
-        `"Lazy arbitrary \\"missing\\" not correctly initialized"`
-      );
-    });
-
-    it('should throw on generate if tie receives an invalid parameter after creation', () => {
-      // Arrange
-      const biasFactor = 42;
-      const { arb1 } = letrec((tie) => {
-        const { instance: simpleArb, generate } = fakeNextArbitrary();
-        generate.mockImplementation((...args) => tie('missing').generate(...args));
-        return {
-          arb1: simpleArb,
-        };
-      });
-
-      // Act / Assert
-      expect(() => arb1.generate(mrngNoCall, biasFactor)).toThrowErrorMatchingInlineSnapshot(
-        `"Lazy arbitrary \\"missing\\" not correctly initialized"`
-      );
-    });
-
-    it('should accept "reserved" keys as output of builder', () => {
-      // Arrange
-      const biasFactor = 42;
-      const { instance: simpleArb, generate } = fakeNextArbitrary();
-      generate.mockReturnValueOnce(new NextValue(null));
-      const { tie } = letrec((tie) => ({
-        tie: tie('__proto__'),
-        ['__proto__']: tie('__defineGetter__​​'),
-        ['__defineGetter__​​']: tie('__defineSetter__​​'),
-        ['__defineSetter__​​']: tie('__lookupGetter__​​'),
-        ['__lookupGetter__​​']: tie('__lookupSetter__​​'),
-        ['__lookupSetter__​​']: tie('constructor​​'),
-        ['constructor​​']: tie('hasOwnProperty​​'),
-        ['hasOwnProperty​​']: tie('isPrototypeOf​​'),
-        ['isPrototypeOf​​']: tie('propertyIsEnumerable​​'),
-        ['propertyIsEnumerable​​']: tie('toLocaleString​​'),
-        ['toLocaleString​​']: tie('toSource​​'),
-        ['toSource​​']: tie('toString​​'),
-        ['toString​​']: tie('valueOf'),
-        ['valueOf']: simpleArb,
-      }));
-
-      // Act
-      expect(generate).not.toHaveBeenCalled();
-      tie.generate(mrngNoCall, biasFactor);
-
-      // Assert
-      expect(generate).toHaveBeenCalledTimes(1);
-      expect(generate).toHaveBeenCalledWith(mrngNoCall, biasFactor);
-    });
-
-    it('Should accept builders producing objects based on Object.create(null)', () => {
-      // Arrange
-      const biasFactor = 42;
-      const { instance: simpleArb, generate } = fakeNextArbitrary();
-      generate.mockReturnValueOnce(new NextValue(null));
-      const { a } = letrec((tie) =>
-        Object.assign(Object.create(null), {
-          a: tie('b'),
-          b: simpleArb,
-        })
-      );
-
-      // Act
-      expect(generate).not.toHaveBeenCalled();
-      a.generate(mrngNoCall, biasFactor);
-
-      // Assert
-      expect(generate).toHaveBeenCalledTimes(1);
-      expect(generate).toHaveBeenCalledWith(mrngNoCall, biasFactor);
-    });
-  });
-
-  describe('canGenerate', () => {
-    it.each`
-      expectedStatus
-      ${false}
-      ${true}
-    `('should call canGenerate on the targets', ({ expectedStatus }) => {
-      // Arrange
-      const expectedValue = Symbol();
-      const { instance: simpleArb, canGenerate } = fakeNextArbitrary();
-      canGenerate.mockReturnValueOnce(expectedStatus);
-      const { arb1 } = letrec((tie) => {
-        return {
-          arb1: tie('arb2'),
-          arb2: simpleArb,
-        };
-      });
-
-      // Act
-      const out = arb1.canGenerate(expectedValue);
-
-      // Assert
-      expect(canGenerate).toHaveBeenCalledTimes(1);
-      expect(canGenerate).toHaveBeenCalledWith(expectedValue);
-      expect(out).toBe(expectedStatus);
-    });
-
-    it('should throw on canGenerate if tie receives an invalid parameter', () => {
-      // Arrange
-      const expectedValue = Symbol();
-      const { arb1 } = letrec((tie) => ({
-        arb1: tie('missing'),
-      }));
-
-      // Act / Assert
-      expect(() => arb1.canGenerate(expectedValue)).toThrowErrorMatchingInlineSnapshot(
-        `"Lazy arbitrary \\"missing\\" not correctly initialized"`
-      );
-    });
-  });
-
-  describe('shrink', () => {
-    it('should call shrink on the targets', () => {
-      // Arrange
-      const expectedValue = Symbol();
-      const expectedContext = Symbol();
-      const expectedStream = Stream.of(new NextValue(Symbol()));
-      const { instance: simpleArb, shrink } = fakeNextArbitrary();
-      shrink.mockReturnValueOnce(expectedStream);
-      const { arb1 } = letrec((tie) => {
-        return {
-          arb1: tie('arb2'),
-          arb2: simpleArb,
-        };
-      });
-
-      // Act
-      const out = arb1.shrink(expectedValue, expectedContext);
-
-      // Assert
-      expect(shrink).toHaveBeenCalledTimes(1);
-      expect(shrink).toHaveBeenCalledWith(expectedValue, expectedContext);
-      expect(out).toBe(expectedStream);
-    });
-
-    it('should throw on shrink if tie receives an invalid parameter', () => {
-      // Arrange
-      const expectedValue = Symbol();
-      const expectedContext = Symbol();
-      const { arb1 } = letrec((tie) => ({
-        arb1: tie('missing'),
-      }));
-
-      // Act / Assert
-      expect(() => arb1.shrink(expectedValue, expectedContext)).toThrowErrorMatchingInlineSnapshot(
-        `"Lazy arbitrary \\"missing\\" not correctly initialized"`
-      );
-    });
-  });
-
-  describe('LazyArbitrary (internal)', () => {
-    it('should fail to generate when no underlying arbitrary', () => {
-      // Arrange / Act
-      const lazy = new LazyArbitrary('id007');
-
-      // Assert
-      expect(() => lazy.generate(mrngNoCall, 2)).toThrowErrorMatchingInlineSnapshot(
-        `"Lazy arbitrary \\"id007\\" not correctly initialized"`
-      );
-    });
-
-    it('should fail to check canGenerate when no underlying arbitrary', () => {
-      // Arrange / Act
-      const lazy = new LazyArbitrary('id007');
-
-      // Assert
-      expect(() => lazy.canGenerate(1)).toThrowErrorMatchingInlineSnapshot(
-        `"Lazy arbitrary \\"id007\\" not correctly initialized"`
-      );
-    });
-
-    it('should fail to shrink when no underlying arbitrary', () => {
-      // Arrange / Act
-      const lazy = new LazyArbitrary('id007');
-
-      // Assert
-      expect(() => lazy.shrink(1, 2)).toThrowErrorMatchingInlineSnapshot(
-        `"Lazy arbitrary \\"id007\\" not correctly initialized"`
-      );
-    });
-  });
-});
diff --git a/test/unit/check/arbitrary/StreamArbitrary.spec.ts b/test/unit/arbitrary/StreamArbitrary.spec.ts
similarity index 88%
rename from test/unit/check/arbitrary/StreamArbitrary.spec.ts
rename to test/unit/arbitrary/StreamArbitrary.spec.ts
index 43bd6c27..c4fa0597 100644
--- a/test/unit/check/arbitrary/StreamArbitrary.spec.ts
+++ b/test/unit/arbitrary/StreamArbitrary.spec.ts
@@ -1,14 +1,14 @@
-import * as fc from '../../../../lib/fast-check';
+import * as fc from '../../../lib/fast-check';
 
-import { context } from '../../../../src/arbitrary/context';
-import { nat } from '../../../../src/arbitrary/nat';
-import { infiniteStream } from '../../../../src/check/arbitrary/StreamArbitrary';
-import { Stream } from '../../../../src/stream/Stream';
+import { context } from '../../../src/arbitrary/context';
+import { nat } from '../../../src/arbitrary/nat';
+import { infiniteStream } from '../../../src/arbitrary/infiniteStream';
+import { Stream } from '../../../src/stream/Stream';
 
-import * as genericHelper from './generic/GenericArbitraryHelper';
+import * as genericHelper from '../check/arbitrary/generic/GenericArbitraryHelper';
 
-import * as stubRng from '../../stubs/generators';
-import { hasCloneMethod, cloneMethod, WithCloneMethod } from '../../../../src/check/symbols';
+import * as stubRng from '../stubs/generators';
+import { hasCloneMethod, cloneMethod, WithCloneMethod } from '../../../src/check/symbols';
 
 describe('StreamArbitrary', () => {
   describe('infiniteStream', () => {