From 50c4f2a8486a8adf5cd925953d98fe0b6554a57d Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Fri, 25 Oct 2024 19:01:19 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20string-`unit`?= =?UTF-8?q?=20on=20`object`/`anything`=20arbitrary=20(#5366)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Description** The `unit` field has been added pretty recently to `string` in order to offer ways for our users to control in a more granular way what kind of "character" they would like to be generated for their strings. In order not to mix "character" with the characters in JavaScript and to allow any feasible grapheme or combination of code-points to be a valid "character" we refer to them as "unit". This PR adds supports for units of strings from object builders. **Checklist** — _Don't delete this checklist and make sure you do the following before opening the PR_ - [x] The name of my PR follows [gitmoji](https://gitmoji.dev/) specification - [x] My PR references one of several related issues (if any) - [x] New features or breaking changes must come with an associated Issue or Discussion - [x] My PR does not add any new dependency without an associated Issue or Discussion - [x] My PR includes bumps details, please run `yarn bump` and flag the impacts properly - [x] My PR adds relevant tests and they would have failed without my PR (when applicable) **Advanced** - [x] Category: ✨ Introduce new features - [x] Impacts: New flags for finer control on some arbitraries --- .changeset/chilly-apes-watch.md | 5 +++++ .../helpers/QualifiedObjectConstraints.ts | 14 +++++++++++--- .../builders/AnyArbitraryBuilder.spec.ts | 9 ++++++++- .../core-blocks/arbitraries/composites/object.md | 8 +++++--- 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 .changeset/chilly-apes-watch.md diff --git a/.changeset/chilly-apes-watch.md b/.changeset/chilly-apes-watch.md new file mode 100644 index 00000000000..0684b2ef0b3 --- /dev/null +++ b/.changeset/chilly-apes-watch.md @@ -0,0 +1,5 @@ +--- +"fast-check": minor +--- + +✨ Add support for string-`unit` on `object`/`anything` arbitrary diff --git a/packages/fast-check/src/arbitrary/_internals/helpers/QualifiedObjectConstraints.ts b/packages/fast-check/src/arbitrary/_internals/helpers/QualifiedObjectConstraints.ts index 7c877953d12..b57a133da20 100644 --- a/packages/fast-check/src/arbitrary/_internals/helpers/QualifiedObjectConstraints.ts +++ b/packages/fast-check/src/arbitrary/_internals/helpers/QualifiedObjectConstraints.ts @@ -6,6 +6,7 @@ import { fullUnicodeString } from '../../fullUnicodeString'; import { maxSafeInteger } from '../../maxSafeInteger'; import { oneof } from '../../oneof'; import { string } from '../../string'; +import type { StringConstraints } from '../../string'; import { boxedArbitraryBuilder } from '../builders/BoxedArbitraryBuilder'; import type { DepthSize, SizeForArbitrary } from './MaxLengthFromMinLength'; @@ -107,10 +108,17 @@ export interface ObjectConstraints { /** * Replace the arbitrary of strings defaulted for key and values by one able to generate unicode strings with non-ascii characters. * If you override key and/or values constraint, this flag will not apply to your override. + * @deprecated Prefer using `stringUnit` to customize the kind of strings that will be generated by default. * @defaultValue false * @remarks Since 3.19.0 */ withUnicodeString?: boolean; + /** + * Replace the default unit for strings. + * @defaultValue undefined + * @remarks Since 3.23.0 + */ + stringUnit?: StringConstraints['unit']; } /** @internal */ @@ -121,7 +129,7 @@ type ObjectConstraintsOptionalValues = 'depthSize' | 'maxDepth' | 'maxKeys' | 's * @internal */ export type QualifiedObjectConstraints = Required< - Omit + Omit > & Pick; @@ -160,8 +168,8 @@ export function toQualifiedObjectConstraints(settings: ObjectConstraints = {}): function orDefault(optionalValue: T | undefined, defaultValue: T): T { return optionalValue !== undefined ? optionalValue : defaultValue; } - const stringArbitrary = settings.withUnicodeString ? fullUnicodeString : string; - const valueConstraints = { size: settings.size }; + const stringArbitrary = 'stringUnit' in settings ? string : settings.withUnicodeString ? fullUnicodeString : string; + const valueConstraints = { size: settings.size, unit: settings.stringUnit }; return { key: orDefault(settings.key, stringArbitrary(valueConstraints)), values: boxArbitrariesIfNeeded( diff --git a/packages/fast-check/test/unit/arbitrary/_internals/builders/AnyArbitraryBuilder.spec.ts b/packages/fast-check/test/unit/arbitrary/_internals/builders/AnyArbitraryBuilder.spec.ts index ec103a7c28a..49f03620f72 100644 --- a/packages/fast-check/test/unit/arbitrary/_internals/builders/AnyArbitraryBuilder.spec.ts +++ b/packages/fast-check/test/unit/arbitrary/_internals/builders/AnyArbitraryBuilder.spec.ts @@ -103,6 +103,13 @@ describe('anyArbitraryBuilder (integration)', () => { withSparseArray: fc.boolean(), withTypedArray: fc.boolean(), withUnicodeString: fc.boolean(), + stringUnit: fc.constantFrom( + 'grapheme', + 'grapheme-composite', + 'grapheme-ascii', + 'binary', + 'binary-ascii', + ), }, { requiredKeys: [] }, ) @@ -149,7 +156,7 @@ describe('anyArbitraryBuilder (integration)', () => { if (!extra.withTypedArray) { expect(isTypedArray(v)).toBe(false); } - if (!extra.withUnicodeString) { + if (!extra.withUnicodeString && !('stringUnit' in extra)) { expect(stringify(v)).toSatisfy(doesNotIncludeAnySurrogateCharacter); } // No check for !extra.withObjectString as nothing prevent normal string builders to build such strings diff --git a/website/docs/core-blocks/arbitraries/composites/object.md b/website/docs/core-blocks/arbitraries/composites/object.md index 01c5cff4a45..1fc9eb5a817 100644 --- a/website/docs/core-blocks/arbitraries/composites/object.md +++ b/website/docs/core-blocks/arbitraries/composites/object.md @@ -165,7 +165,7 @@ Generate objects (key/values). **Signatures:** - `fc.object()` -- `fc.object({key?, depthSize?, maxDepth?, maxKeys?, size?, withBigInt?, withBoxedValues?, withDate?, withMap?, withNullPrototype?, withObjectString?, withSet?, withTypedArray?, withSparseArray?, withUnicodeString?, values?})` +- `fc.object({key?, depthSize?, maxDepth?, maxKeys?, size?, withBigInt?, withBoxedValues?, withDate?, withMap?, withNullPrototype?, withObjectString?, withSet?, withTypedArray?, withSparseArray?, withUnicodeString?, stringUnit?, values?})` **with:** @@ -183,7 +183,8 @@ Generate objects (key/values). - `withSet?` — default: `false` — _enable `Set` - eg.: `new Set([1, 2, 3])`_ - `withTypedArray?` — default: `false` — _enable typed arrays for ints, uints and floats - eg.: `Int8Array.from([1, 2, 3])`_ - `withSparseArray?` — default: `false` — _enable sparse arrays - eg.: `[1,,,3]`_ -- `withUnicodeString?` — default: `false` — _change the default for `key` and `values` so that they produce unicode strings with non-ascii characters_ +- `withUnicodeString?` — default: `false` — _change the default for `key` and `values` so that they produce unicode strings with non-ascii characters — shadowed by `stringUnit`_ +- `stringUnit?` — default: `undefined` — _customize the set of characters being used by the `string` arbitrary_ - `values?` — default: _booleans, numbers, strings, null and undefined_ — _array of arbitraries producing the root* values - *non-object ones_ **Usages:** @@ -276,7 +277,7 @@ Generate any kind of entities. **Signatures:** - `fc.anything()` -- `fc.anything({key?, depthSize?, maxDepth?, maxKeys?, size?, withBigInt?, withBoxedValues?, withDate?, withMap?, withNullPrototype?, withObjectString?, withSet?, withTypedArray?, withSparseArray?, withUnicodeString?, values?})` +- `fc.anything({key?, depthSize?, maxDepth?, maxKeys?, size?, withBigInt?, withBoxedValues?, withDate?, withMap?, withNullPrototype?, withObjectString?, withSet?, withTypedArray?, withSparseArray?, withUnicodeString?, stringUnit?, values?})` **with:** @@ -295,6 +296,7 @@ Generate any kind of entities. - `withTypedArray?` — default: `false` — _enable typed arrays for ints, uints and floats - eg.: `Int8Array.from([1, 2, 3])`_ - `withSparseArray?` — default: `false` — _enable sparse arrays - eg.: `[1,,,3]`_ - `withUnicodeString?` — default: `false` — _change the default for `key` and `values` so that they produce unicode strings with non-ascii characters_ +- `stringUnit?` — default: `undefined` — _customize the set of characters being used by the `string` arbitrary — shadowed by `stringUnit`_ - `values?` — default: _booleans, numbers, strings, null and undefined_ — _array of arbitraries producing the root* values - *non-object ones_ **Usages:**