Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class ArrayArbitrary<T> extends Arbitrary<T[]> {
// Whenever passing a isEqual to ArrayArbitrary, you also have to filter
// it's output just in case produced values are too small (below minLength)
readonly setBuilder: CustomSetBuilder<Value<T>> | undefined,
readonly customSlices: T[][],
readonly customSlices: readonly (readonly T[])[],
) {
super();
this.lengthArb = integer({ min: minLength, max: maxGeneratedLength });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { SlicedGenerator } from '../interfaces/SlicedGenerator';
export function buildSlicedGenerator<T>(
arb: Arbitrary<T>,
mrng: Random,
slices: T[][],
slices: readonly (readonly T[])[],
biasFactor: number | undefined,
): SlicedGenerator<T> {
// We by-pass any slice-based logic if one of:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export interface ObjectConstraints {
* @defaultValue {@link boolean}, {@link integer}, {@link double}, {@link string}, null, undefined, Number.NaN, +0, -0, Number.EPSILON, Number.MIN_VALUE, Number.MAX_VALUE, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY
* @remarks Since 0.0.7
*/
values?: Arbitrary<unknown>[];
values?: readonly Arbitrary<unknown>[];
/**
* Also generate boxed versions of values
* @defaultValue false
Expand Down Expand Up @@ -150,13 +150,13 @@ function defaultValues(
}

/** @internal */
function boxArbitraries(arbs: Arbitrary<unknown>[]): Arbitrary<unknown>[] {
function boxArbitraries(arbs: readonly Arbitrary<unknown>[]): Arbitrary<unknown>[] {
return arbs.map((arb) => boxedArbitraryBuilder(arb));
}

/** @internal */
function boxArbitrariesIfNeeded(arbs: Arbitrary<unknown>[], boxEnabled: boolean): Arbitrary<unknown>[] {
return boxEnabled ? boxArbitraries(arbs).concat(arbs) : arbs;
function boxArbitrariesIfNeeded(arbs: readonly Arbitrary<unknown>[], boxEnabled: boolean): Arbitrary<unknown>[] {
return boxEnabled ? boxArbitraries(arbs).concat(arbs) : [...arbs];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class SlicedBasedGenerator<T> implements SlicedGenerator<T> {
constructor(
private readonly arb: Arbitrary<T>,
private readonly mrng: Random,
private readonly slices: T[][],
private readonly slices: readonly (readonly T[])[],
private readonly biasFactor: number,
) {}
attemptExact(targetLength: number): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/fast-check/src/arbitrary/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export interface ArrayConstraintsInternal<T> extends ArrayConstraints {
* Each entry must have at least one element of type T into it.
* Each T must be a value acceptable for the arbitrary passed to the array.
*/
experimentalCustomSlices?: T[][];
experimentalCustomSlices?: readonly (readonly T[])[];
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/fast-check/src/arbitrary/webUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface WebUrlConstraints {
* @defaultValue ['http', 'https']
* @remarks Since 1.14.0
*/
validSchemes?: string[];
validSchemes?: readonly string[];
/**
* Settings for {@link webAuthority}
* @defaultValue &#123;&#125;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Test to verify readonly constraint annotations work correctly
* This demonstrates that users can now pass readonly arrays and objects as constraints
*/
import { describe, it, expect } from 'vitest';
import { object } from '../../../src/arbitrary/object';
import { webUrl } from '../../../src/arbitrary/webUrl';
import { boolean } from '../../../src/arbitrary/boolean';
import { integer } from '../../../src/arbitrary/integer';

describe('Readonly constraint support', () => {
it('should accept readonly arrays for ObjectConstraints.values', () => {
const readonlyValues = [boolean(), integer()] as const;

// This should compile and work without errors
const objectArb = object({
values: readonlyValues,
});

// Verify it generates values
const value = objectArb.generate({
nextInt: () => 0,
nextBigInt: () => 0n,
nextDouble: () => 0.5,
}, undefined);

expect(typeof value.value_).toBe('object');
});

it('should accept readonly string arrays for WebUrlConstraints.validSchemes', () => {
const readonlySchemes = ['http', 'https'] as const;

// This should compile and work without errors
const urlArb = webUrl({
validSchemes: readonlySchemes,
});

// Verify it generates values
const value = urlArb.generate({
nextInt: () => 0,
nextBigInt: () => 0n,
nextDouble: () => 0.5,
}, undefined);

expect(typeof value.value_).toBe('string');
expect(value.value_).toMatch(/^https?:\/\//);
});

it('should maintain backward compatibility with mutable arrays', () => {
// Test that mutable arrays still work
const mutableValues = [boolean(), integer()];
const mutableSchemes = ['http', 'https'];

const objectArb = object({ values: mutableValues });
const urlArb = webUrl({ validSchemes: mutableSchemes });

expect(objectArb).toBeDefined();
expect(urlArb).toBeDefined();
});
});