it('should always map the maximal value (minus one if NaN accepted) of the internal integer to the requested maximal date', () =>
    fc.assert(
      fc.property(constraintsArb(), (constraints) => {
        // Arrange
        const withInvalidDates = !constraints.noInvalidDate;
        const { instance, map } = fakeArbitrary<number>();
        const { instance: mappedInstance } = fakeArbitrary<Date>();
        const integer = vi.spyOn(IntegerMock, 'integer');
        integer.mockReturnValue(instance);
        map.mockReturnValue(mappedInstance);

        // Act
        date(constraints);
        const { max: rangeMax } = integer.mock.calls[0][0]!;
        const [mapper] = map.mock.calls[0];
        const maxDate = mapper(withInvalidDates ? rangeMax! - 1 : rangeMax!) as Date;

        // Assert
        if (constraints.max !== undefined) {
          // If max was specified,
          // the highest value of the range requested to integer should map to it
          expect(maxDate).toEqual(constraints.max);
        } else {
          // If max was not specified,
          // the highest value of the range requested to integer should map to the highest possible Date
          expect(maxDate.getTime()).not.toBe(Number.NaN);
          expect(new Date(maxDate.getTime() + 1).getTime()).toBe(Number.NaN);
        }
      }),
    ))

Summary: The test verifies that the internal integer's maximum value maps correctly to the specified maximal Date, adjusting for the acceptance of NaN if applicable. If a max date is defined in `constraints`, the highest integer value should map directly to it; otherwise, it should map to the highest possible Date value.


unknown

it('should always generate dates between min and max (or invalid ones when accepted) given the range and the mapper', () =>
    fc.assert(
      fc.property(constraintsArb(), fc.maxSafeNat(), (constraints, mod) => {
        // Arrange
        const { instance, map } = fakeArbitrary<number>();
        const { instance: mappedInstance } = fakeArbitrary<Date>();
        const integer = vi.spyOn(IntegerMock, 'integer');
        integer.mockReturnValue(instance);
        map.mockReturnValue(mappedInstance);

        // Act
        date(constraints);
        const { min: rangeMin, max: rangeMax } = integer.mock.calls[0][0]!;
        const [mapper] = map.mock.calls[0];
        const d = mapper(rangeMin! + (mod % (rangeMax! - rangeMin! + 1))) as Date;

        // Assert
        if (constraints.noInvalidDate || !Number.isNaN(d.getTime())) {
          expect(d.getTime()).not.toBe(Number.NaN);
          if (constraints.min) expect(d.getTime()).toBeGreaterThanOrEqual(constraints.min.getTime());
          if (constraints.max) expect(d.getTime()).toBeLessThanOrEqual(constraints.max.getTime());
        }
      }),
    ))

Summary: Generated dates should fall within the specified min and max range, or be valid if invalid dates are not accepted.


it('should throw whenever min is an invalid date', () =>
    fc.assert(
      fc.property(invalidMinConstraintsArb(), (constraints) => {
        // Act / Assert
        expect(() => date(constraints)).toThrowError();
      }),
    ))

Summary: The test ensures that passing a constraint with an invalid date for `min` to the `date` function results in an error being thrown.


it('should throw whenever min is greater than max', () =>
    fc.assert(
      fc.property(invalidRangeConstraintsArb(), (constraints) => {
        // Act / Assert
        expect(() => date(constraints)).toThrowError();
      }),
    ))

Summary: An exception is thrown when the `min` date is greater than the `max` date in the date constraints.


it('should directly pass the values not needing any adaptation', () => {
      fc.assert(
        fc.property(
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          fc.anything(),
          fc.anything(),
          (biasFactor, v, c) => {
            // Arrange
            const value = new Value(v, c);
            const { instance, generate, shrink, canShrinkWithoutContext } = fakeArbitrary();
            generate.mockReturnValueOnce(value);
            const { instance: mrng } = fakeRandom();
            const adapterFunction = vi
              .fn<(arg0: any) => AdapterOutput<any>>()
              .mockImplementation((v) => ({ adapted: false, value: v }));

            // Act
            const arb = adapter(instance, adapterFunction);
            const g = arb.generate(mrng, biasFactor);

            // Assert
            expect(g).toBe(value);
            expect(generate).toHaveBeenCalledWith(mrng, biasFactor);
            expect(adapterFunction).toHaveBeenCalledWith(v);
            expect(shrink).not.toHaveBeenCalled();
            expect(canShrinkWithoutContext).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: Values that do not require adaptation should pass through unchanged when processed by the `adapter` function.


it('should return an adapted value when needing adaptations', () => {
      fc.assert(
        fc.property(
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          (biasFactor, v, c, vAdapted) => {
            // Arrange
            const value = new Value(v, c);
            const { instance, generate, shrink, canShrinkWithoutContext } = fakeArbitrary();
            generate.mockReturnValueOnce(value);
            const { instance: mrng } = fakeRandom();
            const adapterFunction = vi
              .fn<(arg0: any) => AdapterOutput<any>>()
              .mockImplementation(() => ({ adapted: true, value: vAdapted }));

            // Act
            const arb = adapter(instance, adapterFunction);
            const g = arb.generate(mrng, biasFactor);

            // Assert
            expect(g).not.toBe(value);
            expect(g.value_).toBe(vAdapted);
            expect(generate).toHaveBeenCalledWith(mrng, biasFactor);
            expect(adapterFunction).toHaveBeenCalledWith(v);
            expect(shrink).not.toHaveBeenCalled();
            expect(canShrinkWithoutContext).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: `adapter` modifies the generated value using an adapter function, confirming that the result differs from the original and matches the adapted value.


it('should be able to shrink any value it generated if not adapted or shrinkable adapted', () => {
      fc.assert(
        fc.property(
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          fc.anything(),
          fc.anything(),
          fc.record({ adapted: fc.boolean(), value: fc.anything() }),
          fc.anything(),
          fc.anything(),
          fc.record({ adapted: fc.boolean(), value: fc.anything() }),
          fc.anything(),
          fc.anything(),
          fc.record({ adapted: fc.boolean(), value: fc.anything() }),
          fc.boolean(),
          (biasFactor, vA, cA, adaptedA, vAA, cAA, adaptedAA, vAB, cAB, adaptedAB, canShrinkIfAdapted) => {
            // Arrange
            fc.pre(allUniques(vA, vAA, vAB)); // check for adapterFunction
            const valueA = new Value(vA, cA);
            const valueAA = new Value(vAA, cAA);
            const valueAB = new Value(vAB, cAB);
            const { instance, generate, shrink, canShrinkWithoutContext } = fakeArbitrary();
            generate.mockReturnValueOnce(valueA);
            shrink.mockReturnValueOnce(Stream.of(valueAA, valueAB));
            canShrinkWithoutContext.mockReturnValue(canShrinkIfAdapted);
            const { instance: mrng } = fakeRandom();
            const adapterFunction = vi
              .fn<(arg0: any) => AdapterOutput<any>>()
              .mockImplementation((v) => (Object.is(v, vA) ? adaptedA : Object.is(v, vAA) ? adaptedAA : adaptedAB));

            // Act
            const arb = adapter(instance, adapterFunction);
            const g = arb.generate(mrng, biasFactor);
            const shrinks = [...arb.shrink(g.value, g.context)];

            // Assert
            expect(generate).toHaveBeenCalledWith(mrng, biasFactor);
            if (!adaptedA.adapted || canShrinkIfAdapted) {
              expect(shrinks).toHaveLength(2);
              if (adaptedAA.adapted) {
                expect(shrinks[0].value_).toBe(adaptedAA.value);
              } else {
                expect(shrinks[0]).toBe(valueAA);
              }
              if (adaptedAB.adapted) {
                expect(shrinks[1].value_).toBe(adaptedAB.value);
              } else {
                expect(shrinks[1]).toBe(valueAB);
              }
              if (adaptedA.adapted) {
                expect(shrink).toHaveBeenCalledWith(adaptedA.value, undefined);
                expect(canShrinkWithoutContext).toHaveBeenCalledWith(adaptedA.value);
              } else {
                expect(shrink).toHaveBeenCalledWith(vA, cA);
                expect(canShrinkWithoutContext).not.toHaveBeenCalled();
              }
            } else {
              expect(shrinks).toHaveLength(0);
              expect(shrink).not.toHaveBeenCalled();
              expect(canShrinkWithoutContext).toHaveBeenCalledWith(adaptedA.value); // returned false
            }
          },
        ),
      );
    })

Summary: The test checks that values generated by an arbitrary can be correctly shrunk, especially when they are not adapted or are shrinkable if adapted.


it('should forward missing context as-is to the underlying arbitrary', () => {
      fc.assert(
        fc.property(
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.record({ adapted: fc.boolean(), value: fc.anything() }),
          fc.anything(),
          fc.anything(),
          fc.record({ adapted: fc.boolean(), value: fc.anything() }),
          (toShrinkvalue, vAA, cAA, adaptedAA, vAB, cAB, adaptedAB) => {
            // Arrange
            fc.pre(allUniques(vAA, vAB)); // check for adapterFunction
            const valueAA = new Value(vAA, cAA);
            const valueAB = new Value(vAB, cAB);
            const { instance, generate, shrink, canShrinkWithoutContext } = fakeArbitrary();
            shrink.mockReturnValueOnce(Stream.of(valueAA, valueAB));
            const adapterFunction = vi
              .fn<(arg0: any) => AdapterOutput<any>>()
              .mockImplementation((v) => (Object.is(v, vAA) ? adaptedAA : adaptedAB));

            // Act
            const arb = adapter(instance, adapterFunction);
            const shrinks = [...arb.shrink(toShrinkvalue, undefined)];

            // Assert
            expect(shrinks).toHaveLength(2);
            if (adaptedAA.adapted) {
              expect(shrinks[0].value_).toBe(adaptedAA.value);
            } else {
              expect(shrinks[0]).toBe(valueAA);
            }
            if (adaptedAB.adapted) {
              expect(shrinks[1].value_).toBe(adaptedAB.value);
            } else {
              expect(shrinks[1]).toBe(valueAB);
            }
            expect(generate).not.toHaveBeenCalled();
            expect(shrink).toHaveBeenCalledWith(toShrinkvalue, undefined);
            expect(canShrinkWithoutContext).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: Forwards missing context to the underlying arbitrary and verifies that the shrink method is called with the undefined context, ensuring the adapter function correctly adapts values based on uniqueness and specified adaptation.


it('should always check against the arbitrary of string with raw when no untoggleAll', () => {
      fc.assert(
        fc.property(fc.string(), fc.boolean(), fc.func(fc.string()), (rawValue, isShrinkable, toggleCase) => {
          // Arrange
          const { instance, canShrinkWithoutContext } = fakeArbitrary();
          canShrinkWithoutContext.mockReturnValueOnce(isShrinkable);

          // Act
          const arb = new MixedCaseArbitrary(instance, toggleCase, undefined);
          const out = arb.canShrinkWithoutContext(rawValue);

          // Assert
          expect(out).toBe(isShrinkable);
          expect(canShrinkWithoutContext).toHaveBeenCalledTimes(1);
          expect(canShrinkWithoutContext).toHaveBeenCalledWith(rawValue);
        }),
      );
    })

Summary: `MixedCaseArbitrary` should match the shrinkability of a string's arbitrary when no `untoggleAll` is specified, verifying the `canShrinkWithoutContext` method.


it('should always check against the arbitrary of string with untoggled when untoggleAll', () => {
      fc.assert(
        fc.property(
          fc.string(),
          fc.string(),
          fc.boolean(),
          fc.func(fc.string()),
          (rawValue, untoggledValue, isShrinkable, toggleCase) => {
            // Arrange
            const { instance, canShrinkWithoutContext } = fakeArbitrary();
            canShrinkWithoutContext.mockReturnValueOnce(isShrinkable);
            const untoggleAll = vi.fn();
            untoggleAll.mockReturnValue(untoggledValue);

            // Act
            const arb = new MixedCaseArbitrary(instance, toggleCase, untoggleAll);
            const out = arb.canShrinkWithoutContext(rawValue);

            // Assert
            expect(out).toBe(isShrinkable);
            expect(canShrinkWithoutContext).toHaveBeenCalledTimes(1);
            expect(canShrinkWithoutContext).toHaveBeenCalledWith(untoggledValue);
          },
        ),
      );
    })

Summary: `canShrinkWithoutContext` should return a boolean indicating if a `rawValue` can be shrunk after being processed by `untoggleAll`, which provides the `untoggledValue`.


it('should only use the first arbitrary to generate values', () => {
      fc.assert(
        fc.property(
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          fc.anything(),
          fc.anything(),
          (biasFactor, vA, cA) => {
            // Arrange
            const {
              instance: generatorArbitrary,
              generate: generateA,
              shrink: shrinkA,
              canShrinkWithoutContext: canShrinkWithoutContextA,
            } = fakeArbitrary();
            const {
              instance: shrinkerArbitrary,
              generate: generateB,
              shrink: shrinkB,
              canShrinkWithoutContext: canShrinkWithoutContextB,
            } = fakeArbitrary();
            generateA.mockReturnValueOnce(new Value(vA, cA));
            const { instance: mrng } = fakeRandom();

            // Act
            const arb = new WithShrinkFromOtherArbitrary(generatorArbitrary, shrinkerArbitrary);
            const g = arb.generate(mrng, biasFactor);

            // Assert
            expect(g.value).toBe(vA);
            expect(generateA).toHaveBeenCalledWith(mrng, biasFactor);
            expect(shrinkA).not.toHaveBeenCalled();
            expect(canShrinkWithoutContextA).not.toHaveBeenCalled();
            expect(generateB).not.toHaveBeenCalled();
            expect(shrinkB).not.toHaveBeenCalled();
            expect(canShrinkWithoutContextB).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: Only the first arbitrary is used to generate values when `WithShrinkFromOtherArbitrary` is invoked, without calling any methods on the second arbitrary.


it('should only use the first arbitrary for values it generated (coming with the context)', () => {
      fc.assert(
        fc.property(
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          (biasFactor, vA, cA, vAA, cAA, vAB, cAB) => {
            // Arrange
            const {
              instance: generatorArbitrary,
              generate: generateA,
              shrink: shrinkA,
              canShrinkWithoutContext: canShrinkWithoutContextA,
            } = fakeArbitrary();
            const {
              instance: shrinkerArbitrary,
              generate: generateB,
              shrink: shrinkB,
              canShrinkWithoutContext: canShrinkWithoutContextB,
            } = fakeArbitrary();
            generateA.mockReturnValueOnce(new Value(vA, cA));
            shrinkA.mockReturnValueOnce(Stream.of(new Value(vAA, cAA), new Value(vAB, cAB)));
            const { instance: mrng } = fakeRandom();

            // Act
            const arb = new WithShrinkFromOtherArbitrary(generatorArbitrary, shrinkerArbitrary);
            const g = arb.generate(mrng, biasFactor);
            const shrinks = [...arb.shrink(g.value, g.context)];

            // Assert
            expect(shrinks).toHaveLength(2);
            expect(shrinks[0].value).toBe(vAA);
            expect(shrinks[1].value).toBe(vAB);
            expect(generateA).toHaveBeenCalledWith(mrng, biasFactor);
            expect(shrinkA).toHaveBeenCalledWith(vA, cA);
            expect(canShrinkWithoutContextA).not.toHaveBeenCalled();
            expect(generateB).not.toHaveBeenCalled();
            expect(shrinkB).not.toHaveBeenCalled();
            expect(canShrinkWithoutContextB).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: The arbitrary should utilize only the first arbitrary for generating and shrinking values it originally generated, while the second arbitrary should remain unused in these operations.


it('should only use the first arbitrary for values it shrunk (coming with the context)', () => {
      fc.assert(
        fc.property(
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          (biasFactor, vA, cA, vAA, cAA, vAB, cAB, vAC, cAC, vABA, cABA) => {
            // Arrange
            const {
              instance: generatorArbitrary,
              generate: generateA,
              shrink: shrinkA,
              canShrinkWithoutContext: canShrinkWithoutContextA,
            } = fakeArbitrary();
            const {
              instance: shrinkerArbitrary,
              generate: generateB,
              shrink: shrinkB,
              canShrinkWithoutContext: canShrinkWithoutContextB,
            } = fakeArbitrary();
            generateA.mockReturnValueOnce(new Value(vA, cA));
            shrinkA.mockReturnValueOnce(Stream.of(new Value(vAA, cAA), new Value(vAB, cAB), new Value(vAC, cAC)));
            shrinkA.mockReturnValueOnce(Stream.of(new Value(vABA, cABA)));
            const { instance: mrng } = fakeRandom();

            // Act
            const arb = new WithShrinkFromOtherArbitrary(generatorArbitrary, shrinkerArbitrary);
            const g = arb.generate(mrng, biasFactor);
            const g2 = [...arb.shrink(g.value, g.context)][1];
            const shrinks = [...arb.shrink(g2.value, g2.context)];

            // Assert
            expect(shrinks).toHaveLength(1);
            expect(shrinks[0].value).toBe(vABA);
            expect(generateA).toHaveBeenCalledWith(mrng, biasFactor);
            expect(shrinkA).toHaveBeenCalledWith(vA, cA);
            expect(shrinkA).toHaveBeenCalledWith(vAB, cAB);
            expect(canShrinkWithoutContextA).not.toHaveBeenCalled();
            expect(generateB).not.toHaveBeenCalled();
            expect(shrinkB).not.toHaveBeenCalled();
            expect(canShrinkWithoutContextB).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: `WithShrinkFromOtherArbitrary` uses only the first arbitrary to shrink values, confirmed by checking the shrinking logic and ensuring the second arbitrary is not utilized.


it('should only use the second arbitrary for values coming without any context', () => {
      fc.assert(
        fc.property(
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          (vA, vAA, cAA, vAB, cAB) => {
            // Arrange
            const {
              instance: generatorArbitrary,
              generate: generateA,
              shrink: shrinkA,
              canShrinkWithoutContext: canShrinkWithoutContextA,
            } = fakeArbitrary();
            const {
              instance: shrinkerArbitrary,
              generate: generateB,
              shrink: shrinkB,
              canShrinkWithoutContext: canShrinkWithoutContextB,
            } = fakeArbitrary();
            shrinkB.mockReturnValueOnce(Stream.of(new Value(vAA, cAA), new Value(vAB, cAB)));

            // Act
            const arb = new WithShrinkFromOtherArbitrary(generatorArbitrary, shrinkerArbitrary);
            const shrinks = [...arb.shrink(vA, undefined)];

            // Assert
            expect(shrinks).toHaveLength(2);
            expect(shrinks[0].value).toBe(vAA);
            expect(shrinks[1].value).toBe(vAB);
            expect(generateA).not.toHaveBeenCalled();
            expect(shrinkA).not.toHaveBeenCalled();
            expect(canShrinkWithoutContextA).not.toHaveBeenCalled();
            expect(generateB).not.toHaveBeenCalled();
            expect(shrinkB).toHaveBeenCalledWith(vA, undefined);
            expect(canShrinkWithoutContextB).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: `WithShrinkFromOtherArbitrary` uses only the second arbitrary's shrink method for values that have no context, ensuring the first arbitrary's methods are not called.


it('should only use the second arbitrary for values shrunk by it (coming with the context)', () => {
      fc.assert(
        fc.property(
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          fc.anything(),
          (biasFactor, vA, vAA, cAA, vAB, cAB, vAC, cAC, vABA, cABA) => {
            // Arrange
            const {
              instance: generatorArbitrary,
              generate: generateA,
              shrink: shrinkA,
              canShrinkWithoutContext: canShrinkWithoutContextA,
            } = fakeArbitrary();
            const {
              instance: shrinkerArbitrary,
              generate: generateB,
              shrink: shrinkB,
              canShrinkWithoutContext: canShrinkWithoutContextB,
            } = fakeArbitrary();
            shrinkB.mockReturnValueOnce(Stream.of(new Value(vAA, cAA), new Value(vAB, cAB), new Value(vAC, cAC)));
            shrinkB.mockReturnValueOnce(Stream.of(new Value(vABA, cABA)));

            // Act
            const arb = new WithShrinkFromOtherArbitrary(generatorArbitrary, shrinkerArbitrary);
            const g2 = [...arb.shrink(vA, undefined)][1];
            const shrinks = [...arb.shrink(g2.value, g2.context)];

            // Assert
            expect(shrinks).toHaveLength(1);
            expect(shrinks[0].value).toBe(vABA);
            expect(generateA).not.toHaveBeenCalled();
            expect(shrinkA).not.toHaveBeenCalled();
            expect(canShrinkWithoutContextA).not.toHaveBeenCalled();
            expect(generateB).not.toHaveBeenCalled();
            expect(shrinkB).toHaveBeenCalledWith(vA, undefined);
            expect(shrinkB).toHaveBeenCalledWith(vAB, cAB);
            expect(canShrinkWithoutContextB).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: `WithShrinkFromOtherArbitrary` uses the second arbitrary only for shrinking values it already provided, ensuring the main arbitrary methods are not called during this process.


it('should wrap waitAll call using act whenever specified', async () =>
      fc.assert(
        fc.asyncProperty(fc.infiniteStream(fc.nat()), async (seeds) => {
          // Arrange
          let actCount = 0;
          const act = (f: () => Promise<void>) => {
            ++actCount;
            return f();
          };
          const nextTaskIndexLengths: number[] = [];
          const nextTaskIndex = buildSeededNextTaskIndex(seeds, nextTaskIndexLengths);
          const taskSelector: TaskSelector<unknown> = { clone: vi.fn(), nextTaskIndex };

          // Act
          const s = new SchedulerImplem(act, taskSelector);
          s.schedule(Promise.resolve(1));
          s.schedule(Promise.resolve(8));
          s.schedule(Promise.resolve(42));

          // Assert
          expect(actCount).toBe(0);
          expect(nextTaskIndex).not.toHaveBeenCalled();
          await s.waitAll();
          expect(actCount).toBe(3);
          expect(nextTaskIndex).toHaveBeenCalledTimes(3);
          expect(nextTaskIndexLengths).toEqual([3, 2, 1]);
        }),
      ))

Summary: `SchedulerImplem` correctly wraps `waitAll` calls with `act`, incrementing the `actCount` and verifying that `nextTaskIndex` is called the expected number of times, matching the decreasing `nextTaskIndexLengths`.


it('should only release the requested number of scheduled promises', async () => {
      const scheduledCount = 10;
      await fc.assert(
        fc.asyncProperty(fc.nat({ max: scheduledCount }), fc.gen(), async (n, g) => {
          // Arrange
          const nextTaskIndex = vi.fn((tasks: ScheduledTask<unknown>[]) => g(fc.nat, { max: tasks.length - 1 }));
          const taskSelector: TaskSelector<unknown> = { clone: vi.fn(), nextTaskIndex };

          // Act
          const s = new SchedulerImplem((f) => f(), taskSelector);
          for (let i = 0; i !== scheduledCount; ++i) {
            s.schedule(Promise.resolve(i));
          }

          // Assert
          await s.waitNext(n);
          expect(s.count()).toBe(scheduledCount - n); // Still (10 - n) pending scheduled tasks
        }),
      );
    })

Summary: `SchedulerImplem` manages the release of only the specified number of scheduled promises, ensuring that the count of remaining tasks is `scheduledCount - n` after processing `n` promises.


it('should wait for more tasks if tasks are not all ready at invocation time', async () => {
      const scheduledCount = 10;
      await fc.assert(
        fc.asyncProperty(fc.nat({ max: scheduledCount }), fc.gen(), async (n, g) => {
          // Arrange
          const seenValues: number[] = [];
          const nextTaskIndex = vi.fn((tasks: ScheduledTask<unknown>[]) => g(fc.nat, { max: tasks.length - 1 }));
          const taskSelector: TaskSelector<unknown> = { clone: vi.fn(), nextTaskIndex };

          // Act
          let queue = delay(-1);
          const s = new SchedulerImplem((f) => f(), taskSelector);
          for (let i = 0; i !== scheduledCount; ++i) {
            queue = queue
              .then(() => delay(0))
              .then(() => s.schedule(Promise.resolve(i)))
              .then((v) => seenValues.push(v));
          }

          // Assert
          await s.waitNext(n);
          expect(seenValues).toEqual([...Array(n)].map((_, i) => i));
        }),
      );
    })

Summary: `SchedulerImplem` ensures that it waits for pending tasks to be ready before processing, even when all tasks are not initialized at the start.


it('should be able to waitAll promises scheduling others', async () =>
      fc.assert(
        fc.asyncProperty(fc.infiniteStream(fc.nat()), async (seeds) => {
          // Arrange
          const status = { done: false };
          const nothingResolved = {
            1: false,
            2: false,
            3: false,
            4: false,
            5: false,
          };
          const everythingResolved = {
            1: true,
            2: true,
            3: true,
            4: true,
            5: true,
          };
          const resolved = { ...nothingResolved };
          const act = (f: () => Promise<void>) => f();
          const nextTaskIndex = buildSeededNextTaskIndex(seeds);
          const taskSelector: TaskSelector<unknown> = { clone: vi.fn(), nextTaskIndex };
          const order: number[] = [];

          // Act
          const s = new SchedulerImplem(act, taskSelector);
          s.schedule(Promise.resolve(1)).then(() => {
            order.push(1);
            resolved[1] = true;
            Promise.all([
              s.schedule(Promise.resolve(2)).then(() => {
                order.push(2);
                resolved[2] = true;
              }),
              s.schedule(Promise.resolve(3)).then(() => {
                order.push(3);
                resolved[3] = true;
                s.schedule(Promise.resolve(4)).then(() => {
                  order.push(4);
                  resolved[4] = true;
                });
              }),
            ]).then(() => {
              s.schedule(Promise.resolve(5)).then(() => {
                order.push(5);
                resolved[5] = true;
                status.done = true;
              });
            });
          });

          // Assert
          expect(status.done).toBe(false);
          expect(resolved).toEqual(nothingResolved);
          await s.waitAll();
          if (status.done) {
            // There are only a few cases that could make 5 resolved via waitAll. Scheduling 5 is the consequence of Promise.all([2, 3]) being resolved.
            // Promise.all is nasty as it costs an extra await. Meaning that if 3 and 4 (a task scheduled when 3 succeeds) have already been resolved,
            // resolving 2 would not be enought to schedule 5 in a visible way for waitAll.
            expect([
              // The following orders should work to include 5 within the waitAll:
              [1, 2, 3, 4, 5],
              [1, 3, 2, 4, 5],
            ]).toContainEqual(order);
          } else {
            expect([
              // But these ones will not work:
              [1, 3, 4, 2],
            ]).toContainEqual(order);

            expect(resolved).toEqual({ ...everythingResolved, 5: false });
            expect(s.count()).toBe(0); // Well, Promise.all just received the last completion it was waiting for...
            await 'just awaiting to get the proper count'; // It needs one extra await to move forward and schedule the item 5
            expect(s.count()).not.toBe(0);
            await s.waitAll(); // extra waitAll should make it pass
          }
          expect(status.done).toBe(true);
          expect(resolved).toEqual(everythingResolved);
        }),
      ))

Summary: The function verifies that the `SchedulerImplem` can correctly manage and resolve scheduled promises, even when tasks are added dynamically, by ensuring that all tasks complete in the expected order or require an additional wait for certain sequences.


it('should be able to schedule new tasks from other tasks and wait them all with waitAll', async () =>
      fc.assert(
        fc.asyncProperty(
          fc.array(
            fc.letrec((tie) => ({
              self: fc.record({
                name: fc.noBias(fc.string({ minLength: 4, maxLength: 4 })),
                children: fc.oneof(
                  fc.constant<ExecutionPlan[]>([]),
                  fc.array(tie('self') as fc.Arbitrary<ExecutionPlan>),
                ),
              }),
            })).self,
            { minLength: 1 },
          ),
          fc.infiniteStream(fc.nat()),
          async (plan, seeds) => {
            // Arrange
            const act = (f: () => Promise<void>) => f();
            const nextTaskIndex = buildSeededNextTaskIndex(seeds);
            const taskSelector: TaskSelector<unknown> = { clone: vi.fn(), nextTaskIndex };
            const computeTasksInPlan = (tasks: ExecutionPlan[]) => {
              let count = 0;
              for (const t of tasks) {
                count += 1 + computeTasksInPlan(t.children);
              }
              return count;
            };
            const schedulePlan = (s: Scheduler, tasks: ExecutionPlan[]) => {
              for (const t of tasks) {
                s.schedule(Promise.resolve(t.name), t.name).then(() => schedulePlan(s, t.children));
              }
            };

            // Act
            const s = new SchedulerImplem(act, taskSelector);
            schedulePlan(s, plan);

            // Assert
            await s.waitAll();
            expect(s.count()).toBe(0);
            expect(s.report()).toHaveLength(computeTasksInPlan(plan));
          },
        ),
      ))

Summary: The test checks that when scheduling tasks based on a hierarchical execution plan, where tasks can spawn additional tasks, all tasks can be successfully completed and waited upon using `waitAll`, ensuring that the scheduler's task count is zero and the report length matches the number of tasks in the execution plan.


it('should take one of the provided slices and return it item by item', () => {
      fc.assert(
        fc.property(
          fc.array(fc.array(fc.anything(), { minLength: 1 }), { minLength: 1 }),
          fc.nat(),
          fc.nat(),
          fc.integer({ min: 2 }),
          (slices, targetLengthMod, selectOneMod, biasFactor) => {
            // Arrange
            const { instance: arb } = fakeArbitrary();
            const { instance: mrng, nextInt } = fakeRandom();
            nextInt
              .mockReturnValueOnce(1) // 1 to go for "value from slices"
              .mockImplementationOnce((min, max) => (selectOneMod % (max - min + 1)) + min);
            const targetLength = slices[targetLengthMod % slices.length].length;

            // Act
            const generator = new SlicedBasedGenerator(arb, mrng, slices, biasFactor);
            const readFromGenerator: unknown[] = [];
            generator.attemptExact(targetLength);
            for (let index = 0; index !== targetLength; ++index) {
              readFromGenerator.push(generator.next().value);
            }

            // Assert
            expect(nextInt).toHaveBeenCalledTimes(2); // only called twice: 1/ to bias to one of the slices 2/ to select which one
            expect(nextInt).toHaveBeenCalledWith(1, biasFactor);
            expect(slices).toContainEqual(readFromGenerator);
          },
        ),
      );
    })

Summary: The test ensures that a `SlicedBasedGenerator` selects one of the provided slices and yields its elements sequentially.


it('should only go for values coming from the source arbitrary when tossing for unbias', () => {
      fc.assert(
        fc.property(
          fc.array(fc.array(fc.anything(), { minLength: 1 }), { minLength: 1 }),
          fc.infiniteStream(fc.anything()),
          fc.nat({ max: 10 }),
          fc.integer({ min: 2 }),
          (slices, streamValues, targetLength, biasFactor) => {
            // Arrange
            const producedValues: unknown[] = [];
            const { instance: arb, generate } = fakeArbitrary();
            generate.mockImplementation(() => {
              const value = streamValues.next().value;
              const context = streamValues.next().value;
              producedValues.push(value);
              return new Value(value, context);
            });
            const { instance: mrng, nextInt } = fakeRandom();
            nextInt.mockImplementation((_min, max) => max); // >min ie in [min+1,max] corresponds to unbiased

            // Act
            const generator = new SlicedBasedGenerator(arb, mrng, slices, biasFactor);
            const readFromGenerator: unknown[] = [];
            generator.attemptExact(targetLength);
            for (let index = 0; index !== targetLength; ++index) {
              readFromGenerator.push(generator.next().value);
            }

            // Assert
            expect(generate).toHaveBeenCalledTimes(targetLength);
            expect(readFromGenerator).toEqual(producedValues);
          },
        ),
      );
    })

Summary: The `SlicedBasedGenerator` only uses values from the source arbitrary when generating an unbiased sequence of a specified length.


it('should only go for values coming from the slices when tossing for bias', () => {
      fc.assert(
        fc.property(
          fc.array(fc.array(fc.anything(), { minLength: 1 }), { minLength: 1 }),
          fc.infiniteStream(fc.nat()),
          fc.nat({ max: 10 }),
          fc.integer({ min: 2 }),
          fc.boolean(),
          (slices, streamModValues, targetLength, biasFactor, withAttemptExact) => {
            // Arrange
            const { instance: arb, generate } = fakeArbitrary();
            const { instance: mrng, nextInt } = fakeRandom();
            const allValuesFromSlices = slices.flat();

            // Act
            const generator = new SlicedBasedGenerator(arb, mrng, slices, biasFactor);
            const readFromGenerator: unknown[] = [];
            if (withAttemptExact) {
              nextInt.mockImplementation((_min, max) => max); // no bias for attemptExact
              generator.attemptExact(targetLength);
            }
            for (let index = 0; index !== targetLength; ++index) {
              let returnedBias = false;
              nextInt.mockImplementation((min, max) => {
                if (!returnedBias) {
                  returnedBias = true;
                  return min; // ask for bias, to make sure we use slices
                }
                return (streamModValues.next().value % (max - min + 1)) + min; // pure random for next calls
              });
              const value = generator.next().value;
              expect(allValuesFromSlices).toContainEqual(value); // should only produce values coming from slices
              readFromGenerator.push(value);
            }

            // Assert
            expect(generate).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: The `SlicedBasedGenerator` should only produce values from the provided slices when bias is requested and should not call the `generate` method.


it('should properly extract all parts of an url', () =>
    fc.assert(
      fc.property(
        fc.webUrl({
          authoritySettings: {
            withIPv4: true,
            withIPv4Extended: true,
            withIPv6: true,
            withPort: true,
            withUserInfo: true,
          },
          withFragments: true,
          withQueryParameters: true,
        }),
        (url) => {
          // Arrange
          const parsed = new URL(url);

          // Act
          const [scheme, authority, , query, fragments] = partsToUrlUnmapper(url);

          // Assert
          expect(scheme).toBe(url.split('://')[0]);
          expect(decodeURIComponent(authority)).toContain(decodeURIComponent(parsed.username));
          expect(decodeURIComponent(authority)).toContain(decodeURIComponent(parsed.password));
          // Cannot assert on hostname: ips are sanitized
          // Cannot assert on pathname: paths are sanitized (eg.: .., .)
          if (parsed.search.length !== 0) {
            expect(decodeURIComponent(query!)).toBe(decodeURIComponent(parsed.search.substring(1)));
          } else {
            expect([null, '']).toContain(query);
          }
          if (parsed.hash.length !== 0) {
            expect(decodeURIComponent(fragments!)).toBe(decodeURIComponent(parsed.hash.substring(1)));
          } else {
            expect([null, '']).toContain(fragments);
          }
        },
      ),
    ))

Summary: `partsToUrlUnmapper` correctly extracts the scheme, authority, query, and fragment components from a given URL.


it('should be able to unmap any mapped value', () =>
    fc.assert(
      fc.property(fc.array(fc.webSegment()), (segments) => {
        // Arrange
        const mapped = segmentsToPathMapper(segments);

        // Act
        const out = segmentsToPathUnmapper(mapped);

        // Assert
        expect(out).toEqual(segments);
      }),
    ))

Summary: The function `segmentsToPathUnmapper` should return the original array of segments when applied to a value mapped by `segmentsToPathMapper`.


it('should be able to unmap any mapped value', () =>
    fc.assert(
      fc.property(
        fc.string({ unit: hexa(), minLength: 8, maxLength: 8 }),
        fc.string({ unit: hexa(), minLength: 8, maxLength: 8 }),
        fc.string({ unit: hexa(), minLength: 8, maxLength: 8 }),
        fc.string({ unit: hexa(), minLength: 8, maxLength: 8 }),
        (a, b, c, d) => {
          // Arrange
          const ins: [string, string, string, string] = [a, b, c, d];
          const mapped = paddedEightsToUuidMapper(ins);

          // Act
          const out = paddedEightsToUuidUnmapper(mapped);

          // Assert
          expect(out).toEqual(ins);
        },
      ),
    ))

Summary: `paddedEightsToUuidUnmapper` reverses the transformation on any string array mapped by `paddedEightsToUuidMapper`, returning the original array.


it('should be able to generate any of the requested values', () =>
      fc.assert(
        fc.property(
          fc.array(fc.anything(), { minLength: 2 }),
          fc.option(fc.integer({ min: 2 }), { nil: undefined }),
          (values, biasFactor) => {
            // Arrange
            const { instance: mrng, nextInt } = fakeRandom();

            // Act / Assert
            const arb = new ConstantArbitrary(values);
            const notSeenValues = [...values];
            for (let idx = 0; idx !== values.length; ++idx) {
              nextInt.mockImplementationOnce((a, _b) => a + idx);
              const g = arb.generate(mrng, biasFactor);
              const index = notSeenValues.findIndex((v) => Object.is(g.value, v));
              expect(index).not.toBe(-1);
              notSeenValues.splice(index, 1);
            }
            expect(notSeenValues).toEqual([]);
          },
        ),
      ))

Summary: `ConstantArbitrary` can generate each value from a given set of requested values.


it("should not mark value as 'canShrinkWithoutContext' if none of the original values is equal regarding Object.is", () => {
      fc.assert(
        fc.property(fc.uniqueArray(fc.anything(), { minLength: 2, comparator: 'SameValue' }), (values) => {
          // Arrange
          const [selectedValue, ...acceptedValues] = values;

          // Act
          const arb = new ConstantArbitrary(acceptedValues);
          const out = arb.canShrinkWithoutContext(selectedValue); // selectedValue is unique for SameValue comparison (Object.is)

          // Assert
          expect(out).toBe(false);
        }),
      );
    })

Summary: A value is not marked as 'canShrinkWithoutContext' if it does not match any original values using `Object.is`.


it('should shrink towards the first value if it was not already this one and to nil otherwise', () =>
      fc.assert(
        fc.property(fc.array(fc.anything(), { minLength: 1 }), fc.nat(), (values, mod) => {
          // Arrange
          const { instance: mrng, nextInt } = fakeRandom();
          nextInt.mockImplementation((a, b) => a + (mod % (b - a + 1)));

          // Act
          const arb = new ConstantArbitrary(values);
          const value = arb.generate(mrng, undefined);
          const shrinks = [...arb.shrink(value.value, value.context)];

          // Assert
          if (Object.is(value.value, values[0])) {
            expect(shrinks.map((v) => v.value)).toEqual([]);
          } else {
            expect(shrinks.map((v) => v.value)).toEqual([values[0]]);
          }
        }),
      ))

Summary: `ConstantArbitrary` shrinks towards the first value of the array if the generated value is not the initial one, and shrinks to an empty array if it is already the first value.


it('should be able to unmap any mapped value', () =>
    fc.assert(
      fc.property(
        fc.uniqueArray(fc.nat({ max: 15 }), { minLength: 1 }),
        fc.nat(),
        fc.string({ unit: hexa() }),
        (versions, diceIndex, tail) => {
          // Arrange
          const index = diceIndex % versions.length;
          const source = index.toString(16) + tail;
          const { versionsApplierMapper, versionsApplierUnmapper } = buildVersionsAppliersForUuid(versions);
          const mapped = versionsApplierMapper(source);

          // Act
          const out = versionsApplierUnmapper(mapped);

          // Assert
          expect(out).toEqual(source);
        },
      ),
    ))

Summary: `VersionsApplierUnmapper` restores any mapped value back to the original source value.


it('should be able to unmap any mapped value', () =>
    fc.assert(
      fc.property(fc.nat({ max: 0xffffffff }), (n) => {
        // Arrange
        const mapped = numberToPaddedEightMapper(n);

        // Act
        const out = numberToPaddedEightUnmapper(mapped);

        // Assert
        expect(out).toBe(n);
      }),
    ))

Summary: The `numberToPaddedEightUnmapper` should correctly reverse the mapping performed by `numberToPaddedEightMapper`, restoring the original value.


it('should only consider the received size when set to Size', () => {
    fc.assert(
      fc.property(
        sizeRelatedGlobalConfigArb,
        sizeArb,
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.boolean(),
        (config, size, lengthA, lengthB, specifiedMaxLength) => {
          // Arrange
          const [minLength, maxLength] = lengthA < lengthB ? [lengthA, lengthB] : [lengthB, lengthA];

          // Act
          const computedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(size, minLength, maxLength, specifiedMaxLength),
          );
          const expectedLength = Math.min(maxLengthFromMinLength(minLength, size), maxLength);

          // Assert
          expect(computedLength).toBe(expectedLength);
        },
      ),
    );
  })

Summary: When set to Size, the function should compute the length considering only the specified size, ensuring the computed length equals the minimum of the maximum length from the size and the maximum length.


it('should behave as its equivalent Size taking into account global settings when receiving a RelativeSize', () => {
    fc.assert(
      fc.property(
        sizeRelatedGlobalConfigArb,
        relativeSizeArb,
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.boolean(),
        (config, size, lengthA, lengthB, specifiedMaxLength) => {
          // Arrange
          const { baseSize: defaultSize = DefaultSize } = config;
          const equivalentSize = relativeSizeToSize(size, defaultSize);
          const [minLength, maxLength] = lengthA < lengthB ? [lengthA, lengthB] : [lengthB, lengthA];

          // Act
          const computedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(size, minLength, maxLength, specifiedMaxLength),
          );
          const expectedLength = maxGeneratedLengthFromSizeForArbitrary(
            equivalentSize,
            minLength,
            maxLength,
            specifiedMaxLength,
          );

          // Assert
          expect(computedLength).toBe(expectedLength);
        },
      ),
    );
  })

Summary: `maxGeneratedLengthFromSizeForArbitrary` should compute the same length as when using an equivalent size derived from `relativeSizeToSize`, accounting for global settings.


it('should limit collection sizes appropriately', () => {
      fc.assert(
        fc.property(
          fc.array(domainArbitraries.curriculumCode, { minLength: 1, maxLength: 100 }),
          (expectations) => {
            // Invariant: Collections should have reasonable size limits
            const maxExpectationsPerLesson = 5;

            // In a real lesson, shouldn't have too many expectations
            return expectations.length <= maxExpectationsPerLesson * 20; // Allow for testing
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: Collection sizes should not exceed a reasonable limit within the specified constraints of the lesson expectations.


it('should behave as its resolved Size when in unspecified max mode', () => {
    fc.assert(
      fc.property(
        sizeRelatedGlobalConfigArb,
        fc.oneof(sizeArb, relativeSizeArb),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        (config, size, lengthA, lengthB) => {
          // Arrange
          const resolvedSize = withConfiguredGlobal(config, () => resolveSize(size));
          const [minLength, maxLength] = lengthA < lengthB ? [lengthA, lengthB] : [lengthB, lengthA];

          // Act
          const computedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(size, minLength, maxLength, false),
          );
          const expectedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(resolvedSize, minLength, maxLength, false),
          );

          // Assert
          expect(computedLength).toBe(expectedLength);
        },
      ),
    );
  })

Summary: The resolved size should determine the computed length when max mode is unspecified, ensuring it matches the expected length with the resolved size applied.


it('should ignore specifiedMaxLength whenever size specified', () => {
    fc.assert(
      fc.property(
        sizeRelatedGlobalConfigArb,
        sizeForArbitraryArb,
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        (config, size, lengthA, lengthB) => {
          // Arrange
          const [minLength, maxLength] = lengthA < lengthB ? [lengthA, lengthB] : [lengthB, lengthA];

          // Act
          const computedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(size, minLength, maxLength, false),
          );
          const expectedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(size, minLength, maxLength, true),
          );

          // Assert
          expect(computedLength).toBe(expectedLength);
        },
      ),
    );
  })

Summary: The computed length should equal the expected length when a size is specified, regardless of `specifiedMaxLength`.


it('should fallback to "max" whenever no size specified but maxLength specified when defaultSizeToMaxWhenMaxSpecified true or unset', () => {
    fc.assert(
      fc.property(
        sizeRelatedGlobalConfigArb,
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        (incompleteConfig, lengthA, lengthB) => {
          // Arrange
          const config = { ...incompleteConfig, defaultSizeToMaxWhenMaxSpecified: true };
          const [minLength, maxLength] = lengthA < lengthB ? [lengthA, lengthB] : [lengthB, lengthA];

          // Act
          const computedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(undefined, minLength, maxLength, true),
          );
          const expectedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary('max', minLength, maxLength, true),
          );

          // Assert
          expect(computedLength).toBe(expectedLength);
        },
      ),
    );
  })

Summary: The test checks whether, in the absence of a specified size but with `maxLength` provided, the generated maximum length defaults to `max` when `defaultSizeToMaxWhenMaxSpecified` is set to true or left unset.


it('should fallback to baseSize (or default) whenever no size specified and no maxLength specified', () => {
    fc.assert(
      fc.property(
        sizeRelatedGlobalConfigArb,
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        (config, lengthA, lengthB) => {
          // Arrange
          const [minLength, maxLength] = lengthA < lengthB ? [lengthA, lengthB] : [lengthB, lengthA];
          const { baseSize: defaultSize = DefaultSize } = config;

          // Act
          const computedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(undefined, minLength, maxLength, false),
          );
          const expectedLength = maxGeneratedLengthFromSizeForArbitrary(defaultSize, minLength, maxLength, false);

          // Assert
          expect(computedLength).toBe(expectedLength);
        },
      ),
    );
  })

Summary: When no size and no maxLength are specified, the function defaults to using baseSize (or a default size) to compute the maximum generated length.


it('should always return a length being between minLength and maxLength', () => {
    fc.assert(
      fc.property(
        sizeRelatedGlobalConfigArb,
        fc.option(sizeForArbitraryArb, { nil: undefined }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.integer({ min: 0, max: MaxLengthUpperBound }),
        fc.boolean(),
        (config, size, lengthA, lengthB, specifiedMaxLength) => {
          // Arrange
          const [minLength, maxLength] = lengthA < lengthB ? [lengthA, lengthB] : [lengthB, lengthA];

          // Act
          const computedLength = withConfiguredGlobal(config, () =>
            maxGeneratedLengthFromSizeForArbitrary(size, minLength, maxLength, specifiedMaxLength),
          );

          // Assert
          expect(computedLength).toBeGreaterThanOrEqual(minLength);
          expect(computedLength).toBeLessThanOrEqual(maxLength);
        },
      ),
    );
  })

Summary: The computed length from `maxGeneratedLengthFromSizeForArbitrary` should always be between `minLength` and `maxLength`.


it('should behave as its equivalent Size taking into account global settings when receiving a RelativeSize', () => {
    fc.assert(
      fc.property(sizeRelatedGlobalConfigArb, relativeSizeArb, fc.boolean(), (config, size, specifiedMaxDepth) => {
        // Arrange
        const { baseSize: defaultSize = DefaultSize } = config;
        const equivalentSize = relativeSizeToSize(size, defaultSize);

        // Act
        const computedDepthBias = withConfiguredGlobal(config, () =>
          depthBiasFromSizeForArbitrary(size, specifiedMaxDepth),
        );
        const expectedDepthBias = depthBiasFromSizeForArbitrary(equivalentSize, false);

        // Assert
        expect(computedDepthBias).toBe(expectedDepthBias);
      }),
    );
  })

Summary: `depthBiasFromSizeForArbitrary` should produce the same result whether using `RelativeSize` with global settings or its equivalent `Size`.


it('should always return 0 if both specifiedMaxDepth and defaultSizeToMaxWhenMaxSpecified are true and size unset', () => {
    fc.assert(
      fc.property(sizeRelatedGlobalConfigArb, (config) => {
        // Arrange / Act
        const computedDepthBias = withConfiguredGlobal({ ...config, defaultSizeToMaxWhenMaxSpecified: true }, () =>
          depthBiasFromSizeForArbitrary(undefined, true),
        );

        // Assert
        expect(computedDepthBias).toBe(0);
      }),
    );
  })

Summary: Returns 0 for computed depth bias when both specifiedMaxDepth and defaultSizeToMaxWhenMaxSpecified are true, and size is unset.


it('should always starts stream with target when try asap is requested (when current not target)', () =>
    fc.assert(
      fc.property(fc.maxSafeInteger(), fc.maxSafeInteger(), (current, target) => {
        // Arrange
        fc.pre(current !== target);

        // Act
        const shrinks = [...shrinkInteger(current, target, true)];

        // Assert
        expect(shrinks).not.toHaveLength(0);
        expect(shrinks[0].value).toBe(target);
        expect(shrinks[0].context).toBe(undefined);
      }),
    ))

Summary: The property should ensure that when shrinking integers with `try asap` requested and the current value is not the target, the resulting shrink sequence begins with the target integer.


it('should never include target in the stream when try asap is not requested', () =>
    fc.assert(
      fc.property(fc.maxSafeInteger(), fc.maxSafeInteger(), (current, target) => {
        // Arrange / Act
        const shrinks = [...shrinkInteger(current, target, false)];
        const values = shrinks.map((v) => v.value);

        // Assert
        expect(values).not.toContain(target);
      }),
    ))

Summary: Shrinking an integer from a current to a target value should not include the target in the results when "try asap" is false.


it('should always set context to be the value of previous entry in the stream', () =>
    fc.assert(
      fc.property(fc.maxSafeInteger(), fc.maxSafeInteger(), fc.boolean(), (current, target, tryAsap) => {
        // Arrange / Act
        const shrinks = [...shrinkInteger(current, target, tryAsap)];

        // Assert
        for (let idx = 1; idx < shrinks.length; ++idx) {
          expect(shrinks[idx].context).toBe(shrinks[idx - 1].value);
        }
      }),
    ))

Summary: Each entry in the `shrinkInteger` stream should set its context to the value of the previous entry.


it('should specify first context of the stream to target if and only if no try asap, undefined otherwise', () =>
    fc.assert(
      fc.property(fc.maxSafeInteger(), fc.maxSafeInteger(), fc.boolean(), (current, target, tryAsap) => {
        // Arrange
        const expectedFirstContext = tryAsap ? undefined : target;

        // Act
        const first = shrinkInteger(current, target, tryAsap).getNthOrLast(0);

        // Assert
        if (first !== null) {
          expect(first.context).toBe(expectedFirstContext);
        }
      }),
    ))

Summary: The test ensures that the first context of a stream from `shrinkInteger` is set to the target value only if `tryAsap` is false; otherwise, it should be undefined.


it('should always return empty stream when current equals target', () =>
    fc.assert(
      fc.property(fc.bigInt(), fc.boolean(), (value, tryAsap) => {
        // Arrange / Act
        const shrinks = [...shrinkBigInt(value, value, tryAsap)];

        // Assert
        expect(shrinks).toHaveLength(0);
      }),
    ))

Summary: The function `shrinkBigInt` returns an empty stream when the `current` equals the `target`.


it('should always starts stream with target when try asap is requested (when current not target)', () =>
    fc.assert(
      fc.property(fc.bigInt(), fc.bigInt(), (current, target) => {
        // Arrange
        fc.pre(current !== target);

        // Act
        const shrinks = [...shrinkBigInt(current, target, true)];

        // Assert
        expect(shrinks).not.toHaveLength(0);
        expect(shrinks[0].value).toBe(target);
        expect(shrinks[0].context).toBe(undefined);
      }),
    ))

Summary: The test verifies that when shrinking a `bigInt` with a different `current` and `target`, and "try asap" is requested, the shrink stream always starts with the `target`.


it('should only include values between current and target in the stream', () =>
    fc.assert(
      fc.property(fc.bigInt(), fc.bigInt(), fc.boolean(), (current, target, tryAsap) => {
        // Arrange / Act
        const shrinks = [...shrinkBigInt(current, target, tryAsap)];
        const values = shrinks.map((v) => v.value);
        const min = (a: bigint, b: bigint) => (a < b ? a : b);
        const max = (a: bigint, b: bigint) => (a < b ? b : a);

        // Assert
        for (const v of values) {
          expect(v).toBeGreaterThanOrEqual(min(current, target));
          expect(v).toBeLessThanOrEqual(max(current, target));
        }
      }),
    ))

Summary: `shrinkBigInt` generates values between the current and target, inclusive, in the shrink stream.


it('should always set context to be the value of previous entry in the stream', () =>
    fc.assert(
      fc.property(fc.bigInt(), fc.bigInt(), fc.boolean(), (current, target, tryAsap) => {
        // Arrange / Act
        const shrinks = [...shrinkBigInt(current, target, tryAsap)];

        // Assert
        for (let idx = 1; idx < shrinks.length; ++idx) {
          expect(shrinks[idx].context).toBe(shrinks[idx - 1].value);
        }
      }),
    ))

Summary: The context of each entry in the `shrinkBigInt` stream should be set to the value of the previous entry.


it('should specify first context of the stream to target if and only if no try asap, undefined otherwise', () =>
    fc.assert(
      fc.property(fc.bigInt(), fc.bigInt(), fc.boolean(), (current, target, tryAsap) => {
        // Arrange
        const expectedFirstContext = tryAsap ? undefined : target;

        // Act
        const first = shrinkBigInt(current, target, tryAsap).getNthOrLast(0);

        // Assert
        if (first !== null) {
          expect(first.context).toBe(expectedFirstContext);
        }
      }),
    ))

Summary: The first context of the stream produced by `shrinkBigInt` should be set to the target when `tryAsap` is false, and undefined otherwise.


it('should always strictly increase distance from target as we move in the stream', () =>
    fc.assert(
      fc.property(fc.bigInt(), fc.bigInt(), fc.boolean(), (current, target, tryAsap) => {
        // Arrange / Act
        const shrinks = [...shrinkBigInt(current, target, tryAsap)];
        const absDiff = (a: bigint, b: bigint): bigint => {
          const result = a - b;
          return result >= 0 ? result : -result;
        };

        // Assert
        for (let idx = 1; idx < shrinks.length; ++idx) {
          const previousDistance = absDiff(shrinks[idx - 1].value, target);
          const currentDistance = absDiff(shrinks[idx].value, target);
          expect(currentDistance).toBeGreaterThan(previousDistance);
        }
      }),
    ))

Summary: The distance from the target should strictly increase with each subsequent element in the `shrinkBigInt` stream.


it('should be able to split strings built out of chunks into chunks', () =>
    fc.assert(
      fc.property(
        // Defining chunks, we allow "" to be part of the chunks as we do not request any minimal length for the 'split into chunks'
        fc.array(fc.string({ unit: 'binary' }), { minLength: 1 }),
        // Array of random natural numbers to help building the source string
        fc.array(fc.nat()),
        (sourceChunks, sourceMods) => {
          // Arrange
          const sourceChunksSet = new Set(sourceChunks);
          const { instance, canShrinkWithoutContext } = fakeArbitrary<string>();
          canShrinkWithoutContext.mockImplementation((value): value is string => sourceChunksSet.has(value as string));
          const source = sourceMods.map((mod) => sourceChunks[mod % sourceChunks.length]).join('');

          // Act
          const unmapper = patternsToStringUnmapperFor(instance, {});
          const chunks = unmapper(source);

          // Assert
          expect(chunks.join('')).toBe(source);
          // Remark: Found chunks may differ from the one we used to build the source
          // For instance:
          // >  sourceChunks = ["ToTo", "To"]
          // >  sourceMods   = [0]
          // >  chunks might be ["To", "To"] or ["ToTo"] and both are valid ones
        },
      ),
    ))

Summary: The property should allow splitting a string built from multiple chunks into chunks such that concatenating the chunks results in the original string, even though the chunks may differ from the original ones used to build the string.


it('should be able to split strings built out of chunks into chunks while respecting constraints in size', () =>
    fc.assert(
      fc.property(
        fc.array(fc.string({ unit: 'binary', minLength: 1 }), { minLength: 1 }),
        fc.array(fc.nat()),
        fc.nat(),
        fc.nat(),
        (sourceChunks, sourceMods, constraintsMinOffset, constraintsMaxOffset) => {
          // Arrange
          const sourceChunksSet = new Set(sourceChunks);
          const { instance, canShrinkWithoutContext } = fakeArbitrary<string>();
          canShrinkWithoutContext.mockImplementation((value): value is string => sourceChunksSet.has(value as string));
          const source = sourceMods.map((mod) => sourceChunks[mod % sourceChunks.length]).join('');
          const constraints = {
            minLength: Math.max(0, sourceMods.length - constraintsMinOffset),
            maxLength: sourceMods.length + constraintsMaxOffset,
          };

          // Act
          const unmapper = patternsToStringUnmapperFor(instance, constraints);
          const chunks = unmapper(source);

          // Assert
          expect(chunks.join('')).toBe(source);
          expect(chunks.length).toBeGreaterThanOrEqual(constraints.minLength);
          expect(chunks.length).toBeLessThanOrEqual(constraints.maxLength);
        },
      ),
    ))

Summary: Splits a string built from chunks into chunks that adhere to specified size constraints, ensuring the joined chunks reconstruct the original string.


it('should return false if passed value does not have the right length', () =>
      fc.assert(
        fc.property(fc.nat({ max: 1000 }), fc.nat({ max: 1000 }), (numValues, numRequestedValues) => {
          // Arrange
          fc.pre(numValues !== numRequestedValues);
          const { instance: sourceArb, canShrinkWithoutContext } = fakeArbitrary();

          // Act
          const arb = new CloneArbitrary(sourceArb, numValues);
          const out = arb.canShrinkWithoutContext([...Array(numRequestedValues)]);

          // Assert
          expect(out).toBe(false);
          expect(canShrinkWithoutContext).not.toHaveBeenCalled();
        }),
      ))

Summary: `CloneArbitrary.canShrinkWithoutContext` returns false when the length of the provided array does not match the expected number of values.


it('should be able to unmap any mapped value', () =>
    fc.assert(
      fc.property(fc.maxSafeNat(), fc.integer({ min: 6, max: 20 }), (input, length) => {
        // Arrange
        const mapped = paddedUintToBase32StringMapper(length)(input);
        // Act
        const out = uintToBase32StringUnmapper(mapped);
        // Assert
        expect(out).toEqual(input);
      }),
    ))

Summary: The property ensures that mapping an integer to a base32 string and then unmapping it returns the original integer, verifying the inverse relationship between `paddedUintToBase32StringMapper` and `uintToBase32StringUnmapper`.


it('should concat all the generated values together when no set constraints ', () => {
      fc.assert(
        fc.property(
          fc.array(fc.tuple(fc.anything(), fc.anything())),
          fc.nat(),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.anything(),
          (generatedValues, seed, aLength, bLength, integerContext) => {
            // Arrange
            const { acceptedValues, instance, generate } = prepareSetBuilderData(generatedValues, false);
            const { minLength, maxGeneratedLength, maxLength } = extractLengths(seed, aLength, bLength, acceptedValues);
            const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();
            generateInteger.mockReturnValue(new Value(acceptedValues.size, integerContext));
            const integer = vi.spyOn(IntegerMock, 'integer');
            integer.mockReturnValue(integerInstance);
            const { instance: mrng } = fakeRandom();

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              undefined,
              [],
            );
            const g = arb.generate(mrng, undefined);

            // Assert
            expect(g.hasToBeCloned).toBe(false);
            expect(g.value).toEqual([...acceptedValues].map((v) => v.value));
            expect(integer).toHaveBeenCalledTimes(1);
            expect(integer).toHaveBeenCalledWith({ min: minLength, max: maxGeneratedLength });
            expect(generateInteger).toHaveBeenCalledTimes(1);
            expect(generateInteger).toHaveBeenCalledWith(mrng, undefined);
            expect(generate).toHaveBeenCalledTimes(acceptedValues.size);
            for (const call of generate.mock.calls) {
              expect(call).toEqual([mrng, undefined]);
            }
          },
        ),
      );
    })

Summary: Concatenation of generated values occurs when there are no set constraints, matching the values against the accepted set and ensuring the length constraints are respected.


it("should not concat all the values together in case they don't follow set contraints", () => {
      fc.assert(
        fc.property(
          fc.array(fc.tuple(fc.anything(), fc.anything(), fc.boolean())),
          fc.nat(),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.anything(),
          (generatedValues, seed, aLength, bLength, integerContext) => {
            // Arrange
            const { acceptedValues, instance, generate, setBuilder } = prepareSetBuilderData(generatedValues, false);
            const { minLength, maxGeneratedLength, maxLength } = extractLengths(seed, aLength, bLength, acceptedValues);
            const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();
            generateInteger.mockReturnValue(new Value(acceptedValues.size, integerContext));
            const integer = vi.spyOn(IntegerMock, 'integer');
            integer.mockReturnValue(integerInstance);
            const { instance: mrng } = fakeRandom();

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              setBuilder,
              [],
            );
            const g = arb.generate(mrng, undefined);

            // Assert
            expect(g.hasToBeCloned).toBe(false);
            // In the case of set the generated value might be smaller
            // The generator is allowed to stop whenever it considers at already tried to many times (maxGeneratedLength times)
            expect(g.value).toEqual([...acceptedValues].map((v) => v.value).slice(0, g.value.length));
            expect(integer).toHaveBeenCalledTimes(1);
            expect(integer).toHaveBeenCalledWith({ min: minLength, max: maxGeneratedLength });
            expect(generateInteger).toHaveBeenCalledTimes(1);
            expect(generateInteger).toHaveBeenCalledWith(mrng, undefined);
            expect(setBuilder).toHaveBeenCalledTimes(1);
            for (const call of generate.mock.calls) {
              expect(call).toEqual([mrng, undefined]);
            }
          },
        ),
      );
    })

Summary: Generated values that do not conform to set constraints are not concatenated together, ensuring only valid values are used in the array.


it('should bias depth the same way for any child and reset it at the end', () => {
      fc.assert(
        fc.property(
          fc.array(fc.tuple(fc.anything(), fc.anything(), fc.boolean())),
          fc.nat(),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.anything(),
          fc.integer({ min: 2 }),
          fc.boolean(),
          (generatedValues, seed, aLength, bLength, integerContext, biasFactor, withSetBuilder) => {
            // Arrange
            const getDepthContextFor = vi.spyOn(DepthContextMock, 'getDepthContextFor');
            const depthContext = { depth: 0 };
            getDepthContextFor.mockReturnValue(depthContext);
            const seenDepths = new Set<number>();
            const { acceptedValues, instance, generate, setBuilder } = prepareSetBuilderData(
              generatedValues,
              !withSetBuilder,
              () => {
                seenDepths.add(depthContext.depth);
              },
            );
            const { minLength, maxGeneratedLength, maxLength } = extractLengths(seed, aLength, bLength, acceptedValues);
            const { instance: integerInstance, generate: generateInteger } = fakeArbitrary();
            generateInteger.mockReturnValue(new Value(minLength, integerContext));
            const integer = vi.spyOn(IntegerMock, 'integer');
            integer.mockReturnValue(integerInstance);
            const { instance: mrng } = fakeRandom();

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              withSetBuilder ? setBuilder : undefined,
              [],
            );
            arb.generate(mrng, biasFactor);

            // Assert
            expect(getDepthContextFor).toHaveBeenCalledTimes(1); // only array calls it in the test
            expect(depthContext.depth).toBe(0); // properly reset
            if (generate.mock.calls.length !== 0) {
              expect([...seenDepths]).toHaveLength(1); // always called with same depth
            } else {
              expect([...seenDepths]).toHaveLength(0); // never called on items
            }
          },
        ),
      );
    })

Summary: The `ArrayArbitrary` should consistently manage depth for each generated child and reset the depth at the end of array generation.


it('should reject any array not matching the requirements on length', () => {
      fc.assert(
        fc.property(
          fc.array(fc.anything()),
          fc.boolean(),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          (value, withSetBuilder, aLength, bLength, cLength) => {
            // Arrange
            const [minLength, maxGeneratedLength, maxLength] = [aLength, bLength, cLength].sort((a, b) => a - b);
            fc.pre(value.length < minLength || value.length > maxLength);
            const { instance, canShrinkWithoutContext } = fakeArbitrary();
            const data: any[] = [];
            const customSet: CustomSet<Value<any>> = {
              size: () => data.length,
              getData: () => data,
              tryAdd: (vTest) => {
                data.push(vTest.value_);
                return true;
              },
            };
            const setBuilder = vi.fn();
            setBuilder.mockReturnValue(customSet);

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              withSetBuilder ? setBuilder : undefined,
              [],
            );
            const out = arb.canShrinkWithoutContext(value);

            // Assert
            expect(out).toBe(false);
            expect(canShrinkWithoutContext).not.toHaveBeenCalled();
            expect(setBuilder).not.toHaveBeenCalled();
          },
        ),
      );
    })

Summary: Arrays that do not meet specified length requirements should be rejected by returning false from `canShrinkWithoutContext`.


it('should reject any array with at least one entry rejected by the sub-arbitrary', () => {
      fc.assert(
        fc.property(
          fc.uniqueArray(fc.tuple(fc.anything(), fc.boolean()), {
            minLength: 1,
            selector: (v) => v[0],
            comparator: 'SameValue',
          }),
          fc.boolean(),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          (value, withSetBuilder, offsetMin, offsetMax, maxGeneratedLength) => {
            // Arrange
            fc.pre(value.some((v) => !v[1]));
            const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);
            const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);
            const { instance, canShrinkWithoutContext } = fakeArbitrary();
            canShrinkWithoutContext.mockImplementation(
              (vTest): vTest is any => value.find((v) => Object.is(v[0], vTest))![1],
            );
            const data: any[] = [];
            const customSet: CustomSet<Value<any>> = {
              size: () => data.length,
              getData: () => data,
              tryAdd: (vTest) => {
                data.push(vTest.value_);
                return true;
              },
            };
            const setBuilder = vi.fn();
            setBuilder.mockReturnValue(customSet);

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              withSetBuilder ? setBuilder : undefined,
              [],
            );
            const out = arb.canShrinkWithoutContext(value.map((v) => v[0]));

            // Assert
            expect(out).toBe(false);
            expect(canShrinkWithoutContext).toHaveBeenCalled();
          },
        ),
      );
    })

Summary: Arrays containing at least one element rejected by the sub-arbitrary should not shrink without context.


it('should reject any array not matching requirements for set constraints', () => {
      fc.assert(
        fc.property(
          fc.uniqueArray(fc.tuple(fc.anything(), fc.boolean()), {
            minLength: 1,
            selector: (v) => v[0],
            comparator: 'SameValue',
          }),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          (value, offsetMin, offsetMax, maxGeneratedLength) => {
            // Arrange
            fc.pre(value.some((v) => !v[1]));
            const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);
            const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);
            const { instance, canShrinkWithoutContext } = fakeArbitrary();
            canShrinkWithoutContext.mockReturnValue(true);
            const data: any[] = [];
            const customSet: CustomSet<Value<any>> = {
              size: () => data.length,
              getData: () => data,
              tryAdd: (vTest) => {
                if (value.find((v) => Object.is(v[0], vTest.value_))![1]) {
                  data.push(vTest.value_);
                  return true;
                }
                return false;
              },
            };
            const setBuilder = vi.fn();
            setBuilder.mockReturnValue(customSet);

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              setBuilder,
              [],
            );
            const out = arb.canShrinkWithoutContext(value.map((v) => v[0]));

            // Assert
            expect(out).toBe(false);
            expect(canShrinkWithoutContext).toHaveBeenCalled();
            expect(setBuilder).toHaveBeenCalled();
          },
        ),
      );
    })

Summary: The test ensures that any array not fulfilling specific set constraints results in `ArrayArbitrary` being unable to shrink the array without context, thus returning false.


it('should reject any sparse array', () => {
      fc.assert(
        fc.property(
          fc.sparseArray(fc.anything()),
          fc.boolean(),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          (value, withSetBuilder, offsetMin, offsetMax, maxGeneratedLength) => {
            // Arrange
            fc.pre(value.length !== Object.keys(value).length);
            const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);
            const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);
            const { instance, canShrinkWithoutContext } = fakeArbitrary();
            canShrinkWithoutContext.mockReturnValue(true);
            const data: any[] = [];
            const customSet: CustomSet<Value<any>> = {
              size: () => data.length,
              getData: () => data,
              tryAdd: (vTest) => {
                data.push(vTest.value_);
                return true;
              },
            };
            const setBuilder = vi.fn();
            setBuilder.mockReturnValue(customSet);

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              withSetBuilder ? setBuilder : undefined,
              [],
            );
            const out = arb.canShrinkWithoutContext(value);

            // Assert
            expect(out).toBe(false);
          },
        ),
      );
    })

Summary: Rejection of sparse arrays occurs when the array's length does not match the number of defined keys, resulting in `canShrinkWithoutContext` returning false.


it('should accept all other arrays', () => {
      fc.assert(
        fc.property(
          fc.array(fc.anything()),
          fc.boolean(),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          fc.nat(MaxLengthUpperBound),
          (value, withSetBuilder, offsetMin, offsetMax, maxGeneratedLength) => {
            // Arrange
            const minLength = Math.min(Math.max(0, value.length - offsetMin), maxGeneratedLength);
            const maxLength = Math.max(Math.min(MaxLengthUpperBound, value.length + offsetMax), maxGeneratedLength);
            const { instance, canShrinkWithoutContext } = fakeArbitrary();
            canShrinkWithoutContext.mockReturnValue(true);
            const data: any[] = [];
            const customSet: CustomSet<Value<any>> = {
              size: () => data.length,
              getData: () => data,
              tryAdd: (vTest) => {
                data.push(vTest.value_);
                return true;
              },
            };
            const setBuilder = vi.fn();
            setBuilder.mockReturnValue(customSet);

            // Act
            const arb = new ArrayArbitrary(
              instance,
              minLength,
              maxGeneratedLength,
              maxLength,
              undefined,
              withSetBuilder ? setBuilder : undefined,
              [],
            );
            const out = arb.canShrinkWithoutContext(value);

            // Assert
            expect(out).toBe(true);
          },
        ),
      );
    })

Summary: `ArrayArbitrary` can successfully handle any array input, ensuring that the output maintains the ability to shrink without context.


it('should reject any subdomain with strictly more than 63 characters', () =>
    fc.assert(
      fc.property(fc.string({ unit: alphaChar(), minLength: 64 }), (subdomainLabel) => {
        expect(filterInvalidSubdomainLabel(subdomainLabel)).toBe(false);
      }),
    ))

Summary: `filterInvalidSubdomainLabel` returns false for subdomain labels exceeding 63 characters.


it('should reject any subdomain starting by "xn--"', () =>
    fc.assert(
      fc.property(fc.string({ unit: alphaChar(), maxLength: 63 - 'xn--'.length }), (subdomainLabelEnd) => {
        const subdomainLabel = `xn--${subdomainLabelEnd}`;
        expect(filterInvalidSubdomainLabel(subdomainLabel)).toBe(false);
      }),
    ))

Summary: Subdomains starting with "xn--" should be rejected by `filterInvalidSubdomainLabel`.


it('should not reject subdomains if they start by a substring of "xn--"', () =>
    fc.assert(
      fc.property(
        fc.string({ unit: alphaChar(), maxLength: 63 - 'xn--'.length }),
        fc.nat('xn--'.length - 1),
        (subdomainLabelEnd, keep) => {
          const subdomainLabel = `${'xn--'.substring(0, keep)}${subdomainLabelEnd}`;
          expect(filterInvalidSubdomainLabel(subdomainLabel)).toBe(true);
        },
      ),
    ))

Summary: Subdomains starting with a substring of "xn--" should not be rejected by `filterInvalidSubdomainLabel`.


it('should fulfill fibo(2p-1) = fibo²(p-1)+fibo²(p)', () => {
    // Special case of the property above
    fc.assert(
      fc.property(fc.integer({ min: 1, max: MaxN }), (p) => {
        expect(fibo(2 * p - 1)).toBe(fibo(p - 1) * fibo(p - 1) + fibo(p) * fibo(p));
      }),
    );
  })

Summary: `fibo(2p-1)` should equal `fibo(p-1)² + fibo(p)²` for integers `p`.


it('should fulfill gcd(fibo(a), fibo(b)) = fibo(gcd(a,b))', () => {
    fc.assert(
      fc.property(fc.integer({ min: 1, max: MaxN }), fc.integer({ min: 1, max: MaxN }), (a, b) => {
        const gcd = <T extends bigint | number>(a: T, b: T, zero: T): T => {
          a = a < zero ? (-a as T) : a;
          b = b < zero ? (-b as T) : b;
          if (b > a) {
            const temp = a;
            a = b;
            b = temp;
          }
          // eslint-disable-next-line no-constant-condition
          while (true) {
            if (b == zero) return a;
            a = (a % b) as T;
            if (a == zero) return b;
            b = (b % a) as T;
          }
        };
        expect(gcd(fibo(a), fibo(b), 0n)).toBe(fibo(gcd(a, b, 0)));
      }),
    );
  })

Summary: The greatest common divisor of Fibonacci numbers at positions `a` and `b` should equal the Fibonacci number at the position of the greatest common divisor of `a` and `b`.


it('Should fail if predicate throws anything', () => {
    fc.assert(
      fc.property(fc.anything(), (stuff) => {
        // Arrange
        fc.pre(stuff === null || typeof stuff !== 'object' || !('toString' in stuff));
        const p = property(stubArb.single(8), (_arg: number) => {
          throw stuff;
        });

        // Act
        p.runBeforeEach();
        const out = p.run(p.generate(stubRng.mutable.nocall()).value);
        p.runAfterEach();

        // Assert
        expect(out).toEqual({ error: stuff });
      }),
    );
  })

Summary: A predicate throwing an error should result in a failure with the specific error captured in the output.


it('Should fail if predicate throws anything', () => {
    fc.assert(
      fc.asyncProperty(fc.anything(), async (stuff) => {
        // Arrange
        fc.pre(stuff === null || typeof stuff !== 'object' || !('toString' in stuff));
        const p = asyncProperty(stubArb.single(8), (_arg: number) => {
          throw stuff;
        });

        // Act
        await p.runBeforeEach();
        const out = await p.run(p.generate(stubRng.mutable.nocall()).value);
        await p.runAfterEach();

        // Assert
        expect(out).toEqual({ error: stuff });
      }),
    );
  })

Summary: The test ensures that if a predicate throws an exception, the output captures the thrown value as an error.


test("fuzz `event` w/ `object`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.object(), async (event) => {
			await handler(event, context);
		}),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The function `handler` should handle any object passed as an `event` parameter without errors.


test("fuzz `event` w/ `object`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.object(), async (event) => {
			try {
				await handler(event, context);
			} catch (e) {
				if (e.cause?.package !== "@middy/ws-json-body-parser") {
					throw e;
				}
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The `handler` function should process varied `event` objects without throwing errors related to `@middy/ws-json-body-parser`.


test("fuzz `event` w/ `record`", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				body: fc.string(),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/ws-json-body-parser") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The test verifies that the `handler` function handles a wide range of events with a `body` string without throwing exceptions, except for those specifically caused by `@middy/ws-json-body-parser`.


test("fuzz `event` w/ `object`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.object(), async (event) => {
			try {
				await handler(event, context);
			} catch (e) {
				if (e.cause?.package !== "@middy/ws-router") {
					throw e;
				}
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: `handler` processes an `event` object, and any exception that is not caused by "@middy/ws-router" should be thrown.


test("fuzz `event` w/ `record`", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				requestContext: fc.record({
					routeKey: fc.string(),
				}),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/ws-router") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [[{ requestContext: { routeKey: "valueOf" } }]],
		},
	);
})

Summary: The handler should process events with `requestContext.routeKey` without throwing errors caused by packages other than "@middy/ws-router".


Summary: The `handler` function should handle any object passed as an `event` without errors.


Summary: The function `handler` processes various randomly generated `event` objects without throwing errors.


test("fuzz `event` w/ `record`", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				Records: fc.array(fc.object()),
				response: fc.array(
					fc.record({
						status: fc.constantFrom("pending", "fulfilled", "rejected"),
						reason: fc.string(),
					}),
				),
			}),
			async (event) => {
				await handler(event, context);
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: `handler` processes an `event` with an array of `Records` and a `response`, which includes status and reason, across multiple test cases.


test("fuzz `event` w/ `object`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.object(), async (event) => {
			try {
				await handler(event, context);
			} catch (e) {
				if (e.cause?.package !== "@middy/http-urlencode-body-parser") {
					throw e;
				}
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The test ensures that when the `handler` function processes a fuzzed `event` object, any exceptions thrown are from the package `@middy/http-urlencode-body-parser`.


test("fuzz `event` w/ `record`", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				headers: fc.record({
					"content-type": fc.constant("application/x-www-form-urlencoded"),
				}),
				body: fc.string(),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/http-urlencode-body-parser") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The test ensures that handling an event with a URL-encoded body does not throw unexpected errors outside the expected parser package.


test("fuzz `event` w/ `object`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.object(), async (event) => {
			try {
				await handler(event, context);
			} catch (e) {
				if (e.cause?.package !== "@middy/http-router") {
					throw e;
				}
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The handler function should process various object-shaped `event` inputs without throwing errors related to the `@middy/http-router` package.


test("fuzz `event` w/ `record` ({version: '1.0'})", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				httpMethod: fc.constantFrom(
					"HEAD",
					"OPTIONS",
					"GET",
					"POST",
					"PATCH",
					"DELETE",
					"TRACE",
					"CONNECT",
				),
				path: fc.webPath(),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/http-router") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [
				[{ httpMethod: "valueOf", path: "/" }],
				[{ httpMethod: "GET", path: "valueOf" }],
			],
		},
	);
})

Summary: The handler should correctly process or handle errors for generated HTTP events with specified HTTP methods and paths, ensuring that errors with causes not related to `@middy/http-router` are thrown.


test("fuzz `event` w/ `record` ({version: '2.0'})", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				version: fc.constant("2.0"),
				requestContext: fc.record({
					http: fc.record({
						method: fc.constantFrom(
							"HEAD",
							"OPTIONS",
							"GET",
							"POST",
							"PATCH",
							"DELETE",
							"TRACE",
							"CONNECT",
						),
						path: fc.webPath(),
					}),
				}),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/http-router") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [
				[{ requestContext: { http: { method: "valueOf", path: "/" } } }],
				[{ requestContext: { http: { method: "GET", path: "valueOf" } } }],
			],
		},
	);
})

Summary: The handler should process an event with a version "2.0" and various HTTP methods and paths without errors unrelated to the "@middy/http-router" package.


test("fuzz `event` w/ `record` ({version: '2.0'})", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				version: fc.constant("2.0"),
				requestContext: fc.record({
					http: fc.record({
						method: fc.constantFrom(
							"HEAD",
							"OPTIONS",
							"GET",
							"POST",
							"PATCH",
							"DELETE",
							"TRACE",
							"CONNECT",
						),
						path: fc.webPath(),
					}),
				}),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/http-multipart-body-parser") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The handler should process events with version "2.0" and predefined HTTP methods without incorrectly throwing errors unrelated to `@middy/http-multipart-body-parser`.


test("fuzz `event` w/ `object`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.object(), async (event) => {
			try {
				await handler(event, context);
			} catch (e) {
				if (e.cause?.package !== "@middy/http-json-body-parser") {
					throw e;
				}
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The handler should not throw errors with the cause attributed to `@middy/http-json-body-parser` when processing any object as an `event`.


test("fuzz `event` w/ `object`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.object(), async (event) => {
			try {
				await handler(event, context);
			} catch (e) {
				if (e.cause?.package !== "@middy/http-multipart-body-parser") {
					throw e;
				}
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The test ensures that the `handler` function processes various `event` objects without causing unexpected exceptions unrelated to `@middy/http-multipart-body-parser`.


test("fuzz `event` w/ `record`", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				headers: fc.record({
					"content-type": fc.constant("multipart/form-data; boundary="),
				}),
				body: fc.string(),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/http-multipart-body-parser") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,

			examples: [],
		},
	);
})

Summary: The handler processes events with multipart form-data content-type, ensuring any exceptions are not from the `@middy/http-multipart-body-parser` package.


test("fuzz `event` w/ `record`", async () => {
	await fc.assert(
		fc.asyncProperty(
			fc.record({
				RequestType: fc.string(),
				RequestId: fc.string(),
				LogicalResourceId: fc.string(),
				StackId: fc.string(),
			}),
			async (event) => {
				try {
					await handler(event, context);
				} catch (e) {
					if (e.cause?.package !== "@middy/cloudformation-router") {
						throw e;
					}
				}
			},
		),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [[{ requestContext: { routeKey: "valueOf" } }]],
		},
	);
})

Summary: The test runs a handler function with randomly generated event records, ensuring any exceptions thrown are related specifically to the `@middy/cloudformation-router` package.


test('Should replace only elements', () => {
      fc.assert(
        fc.property(fc.array(arb), fc.func(arb), (arr, f) => {
          const obtainedResult = replace(
            f,
            (t): t is any => !Array.isArray(t),
          )(arr);
          const realResult = arr.map((v) => f(v));
          expect(obtainedResult).toStrictEqual(realResult);
        }),
      );
    })

Summary: The `replace` function should transform elements of an array using a provided function, ensuring the output matches the result of applying the function directly to each element in a `map` operation.


test('should leave json objects alone', () => {
    const throwOnReplace = replace(f, (t): t is any => false);
    fc.assert(
      fc.property(fc.json(), (json) => {
        expect(() =>
          expect(throwOnReplace(json)).toStrictEqual(json),
        ).not.toThrow();
      }),
    );
  })

Summary: Replacing within JSON objects does not alter them when the replacement condition is never met.


test('Should leave numbers unchanged when searching for strings', () => {
    const throwOnReplace = replace(
      f,
      (t): t is string => typeof t === 'string',
    );
    const objectArbitrary = fc.object({
      maxDepth: 4,
      withTypedArray: true,
      values: [fc.integer()],
    });
    fc.assert(
      fc.property(objectArbitrary, (obj) => {
        expect(() => throwOnReplace(obj)).not.toThrow();
      }),
    );
  })

Summary: Ensures that applying `replace` to objects containing numbers does not throw an error when searching for strings.


test("fuzz sessionLookup w/ sid", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sid) => {
			try {
				await sessionLookup(sid, {});
			} catch (e) {
				catchError(sid, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `sessionLookup` should not throw unexpected errors when called with arbitrary session identifiers (`sid`).


test("fuzz sessionSelect w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await sessionSelect(sub, testSession.id);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `sessionSelect` should not throw unexpected errors when provided with any input, allowing only specific error messages like "400 Bad Request", "401 Unauthorized", "404 Not Found", and "409 Conflict".


test("fuzz sessionList w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await sessionList(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `sessionList` should either execute without throwing an error or throw one of the expected errors for any input.