Skip to content

Commit ee8ffb6

Browse files
bobzhangclaude
andauthored
feat(quickcheck): Generator::spawn draws from an Arbitrary instance (#3994)
* feat(quickcheck): Generator::spawn draws from an Arbitrary instance Hand-written generator suites routinely mix Arbitrary-based generation into custom combinators (e.g. arbitrary strings inside a structured document generator); until now each project re-derived the same one-liner. Generator::spawn() makes the bridge a core API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: pin explicit seeds in the spawn docstring example and test Review feedback: do not rely on Generator::samples' implicit default seed, so the snapshots stay stable if the default ever changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: make spawn a free function Review feedback: the package's generator constructors (pure, one_of, elements, frequency, int_range, char_range) are free functions; spawn now follows the same convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 5dc2be0 commit ee8ffb6

3 files changed

Lines changed: 36 additions & 0 deletions

File tree

quickcheck/generator.mbt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,27 @@ pub fn[T] Generator::Generator(
2929
{ generate, }
3030
}
3131

32+
///|
33+
/// Creates a generator that draws values from the type's `Arbitrary`
34+
/// instance, for mixing `Arbitrary`-based generation into hand-written
35+
/// generators.
36+
///
37+
/// ```mbt check
38+
/// test "spawn draws from Arbitrary" {
39+
/// let strings : @quickcheck.Generator[String] = @quickcheck.spawn()
40+
/// let lengths = strings.samples(count=3, size=4, seed=37).map(s => s.length())
41+
/// debug_inspect(
42+
/// lengths,
43+
/// content=(
44+
/// #|[3, 2, 1]
45+
/// ),
46+
/// )
47+
/// }
48+
/// ```
49+
pub fn[T : Arbitrary] spawn() -> Generator[T] {
50+
Generator(Arbitrary::arbitrary)
51+
}
52+
3253
///|
3354
/// Runs a generator with an explicit size and random state.
3455
pub fn[T] Generator::run(

quickcheck/generator_test.mbt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,16 @@ test "zip_with and zip_with3 combine generator outputs" {
173173
),
174174
)
175175
}
176+
177+
///|
178+
test "spawn composes with generator combinators" {
179+
let entries = (@quickcheck.spawn() : @quickcheck.Generator[String])
180+
.zip((@quickcheck.spawn() : @quickcheck.Generator[Int]))
181+
.samples(count=3, size=4, seed=37)
182+
debug_inspect(
183+
entries,
184+
content=(
185+
#|[("", 3), ("Z\b", 3), ("", 0)]
186+
),
187+
)
188+
}

quickcheck/pkg.generated.mbti

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pub fn[X : Arbitrary] samples(Int) -> Array[X]
4242

4343
pub fn[T] sized((Int) -> Generator[T]) -> Generator[T]
4444

45+
pub fn[T : Arbitrary] spawn() -> Generator[T]
46+
4547
// Errors
4648

4749
// Types and methods

0 commit comments

Comments
 (0)