diff --git a/.changeset/chilly-bikes-look.md b/.changeset/chilly-bikes-look.md new file mode 100644 index 00000000000..e9aadc4dd8c --- /dev/null +++ b/.changeset/chilly-bikes-look.md @@ -0,0 +1,5 @@ +--- +"fast-check": major +--- + +💥 Drop deprecated `ascii*` (#5280) diff --git a/packages/fast-check/src/arbitrary/ascii.ts b/packages/fast-check/src/arbitrary/ascii.ts deleted file mode 100644 index cf2a4be84e8..00000000000 --- a/packages/fast-check/src/arbitrary/ascii.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Arbitrary } from '../check/arbitrary/definition/Arbitrary'; -import { buildCharacterArbitrary } from './_internals/builders/CharacterArbitraryBuilder'; -import { indexToPrintableIndexMapper, indexToPrintableIndexUnmapper } from './_internals/mappers/IndexToPrintableIndex'; - -/** - * For single ascii characters - char code between 0x00 (included) and 0x7f (included) - * @deprecated Please use ${@link string} with `fc.string({ unit: 'binary-ascii', minLength: 1, maxLength: 1 })` instead - * @remarks Since 0.0.1 - * @public - */ -export function ascii(): Arbitrary { - return buildCharacterArbitrary(0x00, 0x7f, indexToPrintableIndexMapper, indexToPrintableIndexUnmapper); -} diff --git a/packages/fast-check/src/arbitrary/asciiString.ts b/packages/fast-check/src/arbitrary/asciiString.ts deleted file mode 100644 index 412daa259de..00000000000 --- a/packages/fast-check/src/arbitrary/asciiString.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Arbitrary } from '../check/arbitrary/definition/Arbitrary'; -import type { ArrayConstraintsInternal } from './array'; -import { array } from './array'; -import { ascii } from './ascii'; -import type { StringSharedConstraints } from './_shared/StringSharedConstraints'; -import { codePointsToStringMapper, codePointsToStringUnmapper } from './_internals/mappers/CodePointsToString'; -import { createSlicesForStringLegacy } from './_internals/helpers/SlicesForStringBuilder'; -export type { StringSharedConstraints } from './_shared/StringSharedConstraints'; - -const safeObjectAssign = Object.assign; - -/** - * For strings of {@link ascii} - * - * @param constraints - Constraints to apply when building instances (since 2.4.0) - * - * @deprecated Please use ${@link string} with `fc.string({ unit: 'binary-ascii', ...constraints })` instead - * @remarks Since 0.0.1 - * @public - */ -export function asciiString(constraints: StringSharedConstraints = {}): Arbitrary { - const charArbitrary = ascii(); - const experimentalCustomSlices = createSlicesForStringLegacy(charArbitrary, codePointsToStringUnmapper); - // TODO - Move back to object spreading as soon as we bump support from es2017 to es2018+ - const enrichedConstraints: ArrayConstraintsInternal = safeObjectAssign(safeObjectAssign({}, constraints), { - experimentalCustomSlices, - }); - return array(charArbitrary, enrichedConstraints).map(codePointsToStringMapper, codePointsToStringUnmapper); -} diff --git a/packages/fast-check/src/fast-check-default.ts b/packages/fast-check/src/fast-check-default.ts index 094cdc9967b..f782d3ad931 100644 --- a/packages/fast-check/src/fast-check-default.ts +++ b/packages/fast-check/src/fast-check-default.ts @@ -33,7 +33,6 @@ import { bigUintN } from './arbitrary/bigUintN'; import { boolean } from './arbitrary/boolean'; import type { FalsyContraints, FalsyValue } from './arbitrary/falsy'; import { falsy } from './arbitrary/falsy'; -import { ascii } from './arbitrary/ascii'; import { base64 } from './arbitrary/base64'; import { char } from './arbitrary/char'; import { char16bits } from './arbitrary/char16bits'; @@ -107,7 +106,6 @@ import type { } from './arbitrary/uniqueArray'; import { uniqueArray } from './arbitrary/uniqueArray'; import { infiniteStream } from './arbitrary/infiniteStream'; -import { asciiString } from './arbitrary/asciiString'; import { base64String } from './arbitrary/base64String'; import { fullUnicodeString } from './arbitrary/fullUnicodeString'; import { hexaString } from './arbitrary/hexaString'; @@ -361,7 +359,6 @@ export { bigInt, bigUint, char, - ascii, char16bits, unicode, fullUnicode, @@ -369,7 +366,6 @@ export { base64, mixedCase, string, - asciiString, string16bits, stringOf, unicodeString, diff --git a/packages/fast-check/test/e2e/GenerateAllValues.spec.ts b/packages/fast-check/test/e2e/GenerateAllValues.spec.ts index d3ecd9a844b..1e133afbfe6 100644 --- a/packages/fast-check/test/e2e/GenerateAllValues.spec.ts +++ b/packages/fast-check/test/e2e/GenerateAllValues.spec.ts @@ -31,9 +31,6 @@ describe(`Generate all values (seed: ${seed})`, () => { describe('fc.char()', () => { it('Should be able to produce any printable character', () => lookForMissing(fc.char(), 95)); }); - describe('fc.ascii()', () => { - it('Should be able to produce any character from ascii', () => lookForMissing(fc.ascii(), 128)); - }); describe('fc.char16bits()', () => { it('Should be able to produce any 16 bits character', () => lookForMissing(fc.char16bits(), 65536)); }); diff --git a/packages/fast-check/test/e2e/NoRegression.spec.ts b/packages/fast-check/test/e2e/NoRegression.spec.ts index 37dad230135..002eca4a11b 100644 --- a/packages/fast-check/test/e2e/NoRegression.spec.ts +++ b/packages/fast-check/test/e2e/NoRegression.spec.ts @@ -156,16 +156,6 @@ describe(`NoRegression`, () => { ), ).toThrowErrorMatchingSnapshot(); }); - it('asciiString', () => { - expect( - runWithSanitizedStack(() => - fc.assert( - fc.property(fc.asciiString(), (v) => testFunc(v)), - settings, - ), - ), - ).toThrowErrorMatchingSnapshot(); - }); // // Jest Snapshot seems not to support incomplete surrogate pair correctly // it('string16bits', () => { // expect(runWithSanitizedStack(() => fc.assert(fc.property(fc.string16bits(), v => testFunc(v + v)), settings))).toThrowErrorMatchingSnapshot(); diff --git a/packages/fast-check/test/e2e/Poisoning.spec.ts b/packages/fast-check/test/e2e/Poisoning.spec.ts index b93d3f621f5..3d7d415ebfd 100644 --- a/packages/fast-check/test/e2e/Poisoning.spec.ts +++ b/packages/fast-check/test/e2e/Poisoning.spec.ts @@ -44,7 +44,6 @@ describe(`Poisoning (seed: ${seed})`, () => { { name: 'hexa', arbitraryBuilder: () => fc.hexa() }, { name: 'base64', arbitraryBuilder: () => fc.base64() }, { name: 'char', arbitraryBuilder: () => fc.char() }, - { name: 'ascii', arbitraryBuilder: () => fc.ascii() }, { name: 'unicode', arbitraryBuilder: () => fc.unicode() }, { name: 'char16bits', arbitraryBuilder: () => fc.char16bits() }, { name: 'fullUnicode', arbitraryBuilder: () => fc.fullUnicode() }, @@ -52,7 +51,6 @@ describe(`Poisoning (seed: ${seed})`, () => { { name: 'hexaString', arbitraryBuilder: () => fc.hexaString() }, { name: 'base64String', arbitraryBuilder: () => fc.base64String() }, { name: 'string', arbitraryBuilder: () => fc.string() }, - { name: 'asciiString', arbitraryBuilder: () => fc.asciiString() }, { name: 'unicodeString', arbitraryBuilder: () => fc.unicodeString() }, { name: 'string16bits', arbitraryBuilder: () => fc.string16bits() }, { name: 'fullUnicodeString', arbitraryBuilder: () => fc.fullUnicodeString() }, diff --git a/packages/fast-check/test/e2e/__snapshots__/NoRegression.spec.ts.snap b/packages/fast-check/test/e2e/__snapshots__/NoRegression.spec.ts.snap index ebd403cba4a..5645e80c9db 100644 --- a/packages/fast-check/test/e2e/__snapshots__/NoRegression.spec.ts.snap +++ b/packages/fast-check/test/e2e/__snapshots__/NoRegression.spec.ts.snap @@ -1473,37 +1473,6 @@ Execution summary: . . . . . . . . . . . . . . . . . . . √ [[53219898]]] `; -exports[`NoRegression > asciiString 1`] = ` -[Error: Property failed after 2 tests -{ seed: 42, path: "1:1:1:4:1:1:1:2", endOnFailure: true } -Counterexample: ["\\u0000"] -Shrunk 7 time(s) - -Execution summary: -√ [""] -× ["zWiHt\\u001d(t"] -. √ [""] -. × ["t\\u001d(t"] -. . √ ["(t"] -. . × ["\\u001d(t"] -. . . √ ["(t"] -. . . √ [" (t"] -. . . √ ["^(t"] -. . . √ ["}(t"] -. . . × ["\\u000e(t"] -. . . . √ ["(t"] -. . . . × ["\\u0006(t"] -. . . . . √ ["(t"] -. . . . . × ["\\u0002(t"] -. . . . . . √ ["(t"] -. . . . . . × ["\\u0000(t"] -. . . . . . . √ ["(t"] -. . . . . . . √ ["~(t"] -. . . . . . . × ["\\u0000"] -. . . . . . . . √ [""] -. . . . . . . . √ ["~"]] -`; - exports[`NoRegression > base64String 1`] = ` [Error: Property failed after 3 tests { seed: 42, path: "2:3:5:5", endOnFailure: true } diff --git a/packages/fast-check/test/unit/arbitrary/ascii.spec.ts b/packages/fast-check/test/unit/arbitrary/ascii.spec.ts deleted file mode 100644 index 9c83b77ae0f..00000000000 --- a/packages/fast-check/test/unit/arbitrary/ascii.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { describe, it, expect, vi } from 'vitest'; -import * as fc from 'fast-check'; -import { ascii } from '../../../src/arbitrary/ascii'; - -import { fakeArbitrary } from './__test-helpers__/ArbitraryHelpers'; -import { declareCleaningHooksForSpies } from './__test-helpers__/SpyCleaner'; - -import * as CharacterArbitraryBuilderMock from '../../../src/arbitrary/_internals/builders/CharacterArbitraryBuilder'; -import { - assertProduceValuesShrinkableWithoutContext, - assertProduceCorrectValues, - assertShrinkProducesSameValueWithoutInitialContext, - assertShrinkProducesStrictlySmallerValue, - assertProduceSameValueGivenSameSeed, -} from './__test-helpers__/ArbitraryAssertions'; - -describe('ascii', () => { - declareCleaningHooksForSpies(); - - it('should be able to unmap any mapped value', () => { - // Arrange - const { min, max, mapToCode, unmapFromCode } = extractArgumentsForBuildCharacter(ascii); - - // Act / Assert - fc.assert( - fc.property(fc.integer({ min, max }), (n) => { - expect(unmapFromCode(mapToCode(n))).toBe(n); - }), - ); - }); - - it('should always unmap outside of the range for values it could not have generated', () => { - // Arrange - const { min, max, mapToCode, unmapFromCode } = extractArgumentsForBuildCharacter(ascii); - const allPossibleValues = new Set([...Array(max - min + 1)].map((_, i) => mapToCode(i + min))); - - // Act / Assert - fc.assert( - // [0, 1112063] is the range requested by fullUnicode - fc.property(fc.oneof(fc.integer({ min: -1, max: 1112064 }), fc.maxSafeInteger()), (code) => { - fc.pre(!allPossibleValues.has(code)); // not a possible code for our mapper - const unmapped = unmapFromCode(code); - expect(unmapped < min || unmapped > max).toBe(true); - }), - ); - }); -}); - -describe('ascii (integration)', () => { - const isCorrect = (value: string) => value.length === 1 && 0x00 <= value.charCodeAt(0) && value.charCodeAt(0) <= 0x7f; - - const isStrictlySmaller = (c1: string, c2: string) => remapCharToIndex(c1) < remapCharToIndex(c2); - - const asciiBuilder = () => ascii(); - - it('should produce the same values given the same seed', () => { - assertProduceSameValueGivenSameSeed(asciiBuilder); - }); - - it('should only produce correct values', () => { - assertProduceCorrectValues(asciiBuilder, isCorrect); - }); - - it('should produce values seen as shrinkable without any context', () => { - assertProduceValuesShrinkableWithoutContext(asciiBuilder); - }); - - it('should be able to shrink to the same values without initial context', () => { - assertShrinkProducesSameValueWithoutInitialContext(asciiBuilder); - }); - - it('should preserve strictly smaller ordering in shrink', () => { - assertShrinkProducesStrictlySmallerValue(asciiBuilder, isStrictlySmaller); - }); -}); - -// Helpers - -function extractArgumentsForBuildCharacter(build: () => void) { - const { instance } = fakeArbitrary(); - const buildCharacterArbitrary = vi.spyOn(CharacterArbitraryBuilderMock, 'buildCharacterArbitrary'); - buildCharacterArbitrary.mockImplementation(() => instance); - - build(); - const [min, max, mapToCode, unmapFromCode] = buildCharacterArbitrary.mock.calls[0]; - return { min, max, mapToCode, unmapFromCode }; -} - -function remapCharToIndex(c: string): number { - const cp = c.codePointAt(0)!; - if (cp >= 0x20 && cp <= 0x7e) return cp - 0x20; - if (cp < 0x20) return cp + 0x7e - 0x20 + 1; - return cp; -} diff --git a/packages/fast-check/test/unit/arbitrary/asciiString.spec.ts b/packages/fast-check/test/unit/arbitrary/asciiString.spec.ts deleted file mode 100644 index 89e53f8fe70..00000000000 --- a/packages/fast-check/test/unit/arbitrary/asciiString.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import * as fc from 'fast-check'; -import { asciiString } from '../../../src/arbitrary/asciiString'; - -import { - assertProduceValuesShrinkableWithoutContext, - assertShrinkProducesSameValueWithoutInitialContext, - assertProduceCorrectValues, - assertProduceSameValueGivenSameSeed, -} from './__test-helpers__/ArbitraryAssertions'; - -describe('asciiString (integration)', () => { - type Extra = { minLength?: number; maxLength?: number }; - const extraParameters: fc.Arbitrary = fc - .tuple(fc.nat({ max: 5 }), fc.nat({ max: 30 }), fc.boolean(), fc.boolean()) - .map(([min, gap, withMin, withMax]) => ({ - minLength: withMin ? min : undefined, - maxLength: withMax ? min + gap : undefined, - })); - - const isCorrect = (value: string, extra: Extra) => { - if (extra.minLength !== undefined) { - expect(value.length).toBeGreaterThanOrEqual(extra.minLength); - } - if (extra.maxLength !== undefined) { - expect(value.length).toBeLessThanOrEqual(extra.maxLength); - } - for (const c of value.split('')) { - expect(c.charCodeAt(0)).toBeGreaterThanOrEqual(0x00); - expect(c.charCodeAt(0)).toBeLessThanOrEqual(0x7f); - } - }; - - const asciiStringBuilder = (extra: Extra) => asciiString(extra); - - it('should produce the same values given the same seed', () => { - assertProduceSameValueGivenSameSeed(asciiStringBuilder, { extraParameters }); - }); - - it('should only produce correct values', () => { - assertProduceCorrectValues(asciiStringBuilder, isCorrect, { extraParameters }); - }); - - it('should produce values seen as shrinkable without any context', () => { - assertProduceValuesShrinkableWithoutContext(asciiStringBuilder, { extraParameters }); - }); - - it('should be able to shrink to the same values without initial context', () => { - assertShrinkProducesSameValueWithoutInitialContext(asciiStringBuilder, { extraParameters }); - }); -}); diff --git a/website/docs/core-blocks/arbitraries/primitives/char.md b/website/docs/core-blocks/arbitraries/primitives/char.md index 5d221f0c8ee..20f6c4c0e82 100644 --- a/website/docs/core-blocks/arbitraries/primitives/char.md +++ b/website/docs/core-blocks/arbitraries/primitives/char.md @@ -60,24 +60,6 @@ fc.char(); Resources: [API reference](https://fast-check.dev/api-reference/functions/char.html). Available since 0.0.1. -## ascii - -One ascii character — _ie.: one character between `0x00` (included) and `0x7f` (included)_. - -**Signatures:** - -- `fc.ascii()` — _deprecated since v3.22.0, prefer [string](https://fast-check.dev/docs/core-blocks/arbitraries/primitives/string/#string-1) (more details at [#5233](https://github.com/dubzzz/fast-check/pull/5233))_ - -**Usages:** - -```js -fc.ascii(); -// Examples of generated values: "4", "l", "S", ";", "\u0019"… -``` - -Resources: [API reference](https://fast-check.dev/api-reference/functions/ascii.html). -Available since 0.0.1. - ## unicode One unicode character from BMP-plan — _ie.: one character between `0x0000` (included) and `0xffff` (included) but excluding surrogate pairs (between `0xd800` and `0xdfff`)_. diff --git a/website/docs/core-blocks/arbitraries/primitives/string.md b/website/docs/core-blocks/arbitraries/primitives/string.md index 08cb9f69498..ac5ebac3d24 100644 --- a/website/docs/core-blocks/arbitraries/primitives/string.md +++ b/website/docs/core-blocks/arbitraries/primitives/string.md @@ -117,43 +117,6 @@ fc.string({ unit: fc.constantFrom('Hello', 'World') }); Resources: [API reference](https://fast-check.dev/api-reference/functions/string.html). Available since 0.0.1. -## asciiString - -ASCII string containing characters produced by `fc.ascii()`. - -**Signatures:** - -- `fc.asciiString()` — _deprecated since v3.22.0, prefer [string](https://fast-check.dev/docs/core-blocks/arbitraries/primitives/string/#string-1) (more details at [#5233](https://github.com/dubzzz/fast-check/pull/5233))_ -- `fc.asciiString({minLength?, maxLength?, size?})` — _deprecated since v3.22.0, prefer [string](https://fast-check.dev/docs/core-blocks/arbitraries/primitives/string/#string-1) (more details at [#5233](https://github.com/dubzzz/fast-check/pull/5233))_ - -**with:** - -- `minLength?` — default: `0` — _minimal number of characters (included)_ -- `maxLength?` — default: `0x7fffffff` [more](/docs/configuration/larger-entries-by-default/#size-explained) — _maximal number of characters (included)_ -- `size?` — default: `undefined` [more](/docs/configuration/larger-entries-by-default/#size-explained) — _how large should the generated values be?_ - -**Usages:** - -```js -fc.asciiString(); -// Examples of generated values: "\f@D", "hp", "q#dO~?@", "Qad", "5eHqc"… - -fc.asciiString({ maxLength: 3 }); -// Note: Any ascii string containing up to 3 (included) characters -// Examples of generated values: "6", "", "ty", ",", "k"… - -fc.asciiString({ minLength: 3 }); -// Note: Any ascii string containing at least 3 (included) characters -// Examples of generated values: "603e", "6W\u001b^tR-\n\n|", "efproto_\u001abhasOw", "$\u001c&\u0000R", "apply"… - -fc.asciiString({ minLength: 4, maxLength: 6 }); -// Note: Any ascii string containing between 4 (included) and 6 (included) characters -// Examples of generated values: "<&\u001e\u001b ", "bind", "dnGn\\2", "& % !", "__defi"… -``` - -Resources: [API reference](https://fast-check.dev/api-reference/functions/asciiString.html). -Available since 0.0.1. - ## unicodeString Unicode string containing characters produced by `fc.unicode()`. diff --git a/website/docs/migration/from-3.x-to-4.x.md b/website/docs/migration/from-3.x-to-4.x.md index 7289fe9071a..f7fbb2e0370 100644 --- a/website/docs/migration/from-3.x-to-4.x.md +++ b/website/docs/migration/from-3.x-to-4.x.md @@ -93,6 +93,26 @@ However, we strongly recommend either using the new default behavior or explicit Related pull requests: [#5633](https://github.com/dubzzz/fast-check/pull/5633) +### Changes on strings + +In version 4, we have made significant changes to our string arbitraries to simplify and enhance their usage. + +First, we have removed arbitraries that generated single-character strings. Since generating a single character is equivalent to creating a string with a length of one, these specialized arbitraries were unnecessary. This change helps reduce the API surface and better aligns with typical use cases, as most users require multi-character strings rather than single-character ones. + +Second, we have consolidated our main string arbitraries into a single string arbitrary. Previously, separate arbitraries existed for different character sets, such as ASCII and Unicode. In version 4, these have been unified into a single arbitrary that can be configured using the `unit` constraint to generate specific character types. + +To assist with the migration, here’s how to update your existing code to the new API: + +```diff +--fc.ascii(); +++fc.string({ unit: 'binary-ascii', minLength: 1, maxLength: 1 }); + +--fc.asciiString(); +++fc.string({ unit: 'binary-ascii' }); +``` + +Related pull requests: [#5636](https://github.com/dubzzz/fast-check/pull/5636) + ### Replace any reference to `.noBias` The `.noBias` method, previously available on every `Arbitrary`, was marked as deprecated in version 3.20.0. It has been replaced by a standalone arbitrary with the same functionality. You can prepare for compatibility with the next major version by updating your code as follows: