💥 Support minLength and maxLength on iterator - #7183
Open
dubzzz wants to merge 2 commits into
Open
Conversation
Add support for minLength and maxLength constraints on the iterator arbitrary. By default, generated iterators are mostly finite with lengths computed the same way as for arrays (driven by size), while never-ending iterators still get produced from time to time as the default maxLength is Number.POSITIVE_INFINITY. Mirroring the fc.double idiom for infinity handling: - noDefaultInfinity: true moves the default maxLength to Number.MAX_SAFE_INTEGER so only finite iterators get produced - an explicit finite maxLength also rules out never-ending iterators - minLength: Number.POSITIVE_INFINITY forces only never-ending ones The return type moves from IteratorObject<T, never> to IteratorObject<T, undefined> as generated iterators may now complete. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVQi7vQRR6HQEgp8mJhQVQ
Internal test helpers and specs use fc.iterator as a never-ending source of seeds and shrink paths. Now that iterator defaults to mostly finite iterators, request never-ending ones explicitly through minLength: Number.POSITIVE_INFINITY. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVQi7vQRR6HQEgp8mJhQVQ
🦋 Changeset detectedLatest commit: eb7cb79 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@fast-check/ava
fast-check
@fast-check/jest
@fast-check/packaged
@fast-check/poisoning
@fast-check/vitest
@fast-check/worker
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
From an end-user point of view,
fc.iteratorcan now generate finite iterators, and its constraints let users pick exactly which world they want to live in:minLength?(default:0) — minimal number of items yielded before completing.Number.POSITIVE_INFINITYis accepted and forces every generated iterator to be a never-ending one.maxLength?(default:Number.POSITIVE_INFINITY) — maximal number of items yielded before completing. Any finite value makes every generated iterator finite.noDefaultInfinity?(default:false) — moves the defaultmaxLengthtoNumber.MAX_SAFE_INTEGER, i.e. "only finite iterators, I don't care about the exact cap". An explicitmaxLength: Number.POSITIVE_INFINITYstill wins over it.size?— caps the number of items yielded by finite iterators through the exact same helper asfc.array(maxGeneratedLengthFromSizeForArbitrary),maxLengthstaying the hard upper bound.size: 'max'goes up toNumber.MAX_SAFE_INTEGER(iterators are lazy, so they are not tied to the 2³²−1 bound of arrays).Breaking change (major, changeset included): by default
fc.iterator(arb)no longer produces only never-ending iterators. Most generated iterators are now finite — lengths drawn in[0, 10]with the defaultsize: 'small'— while a never-ending one still shows up from time to time (the target length is drawn with one extra slot abovemaxGeneratedLength; landing on it means never-ending, a 1-in-12 chance with defaults). Users relying on the previous always-infinite behavior migrate withfc.iterator(arb, { minLength: Number.POSITIVE_INFINITY }). As a consequence the return type also moves fromArbitrary<IteratorObject<T, never>>toArbitrary<IteratorObject<T, undefined>>, and a fully-consumed iterator now prints without the trailing/*…*/marker.Why this design: the infinity handling deliberately mirrors the
fc.doubleidiom (min/maxaccepting infinity, plusnoDefaultInfinityto opt out of the infinite default), so the API stays consistent with existing fast-check conventions rather than introducing a new mode flag. The finite lengths reuse the array size machinery sosize,baseSizeanddefaultSizeToMaxWhenMaxSpecifiedbehave as everywhere else — with one deliberate edge case: an infinitemaxLengthis treated as "max not specified" fordefaultSizeToMaxWhenMaxSpecified, since there is no uniform draw over an unbounded range. The drawn target length is decided once per generated value (before cloning), so all clones of a value share the same length and reproducibility by seed is preserved.This PR is focused on that single concern; the snapshot and documentation updates it carries are direct consequences of the new default behavior. Tests added: constraint-resolution and validation cases on
iterator(defaults,noDefaultInfinity, explicit finite/infinite bounds,sizeincl.'max', throwing combinations), and generation-behavior cases onIteratorArbitrary(stops exactly at the drawn length, extra-slot draw producing never-ending iterators, no length draw when forced infinite, completed-iterator printing) plus finite-only and never-ending-only integration assertions — all of which fail without the implementation. Existing tests were migrated to the forced-infinite configuration to keep covering the previous behavior.NoRegressionsnapshots and the auto-generated docs examples were refreshed with the dedicated scripts.Checklist
— Don't delete this checklist and make sure you do the following before opening the PR
pnpm run bumpor by following the instructions from the changeset bot🐛(vitest) Something...) when the change targets a package other thanfast-check🤖 Generated with Claude Code
https://claude.ai/code/session_01FVQi7vQRR6HQEgp8mJhQVQ
Generated by Claude Code