Skip to content

Expose property-based testing helpers as public API#249

Merged
BowTiedRadone merged 11 commits into
masterfrom
lib/simnet-pbt
Apr 22, 2026
Merged

Expose property-based testing helpers as public API#249
BowTiedRadone merged 11 commits into
masterfrom
lib/simnet-pbt

Conversation

@BowTiedRadone
Copy link
Copy Markdown
Contributor

@BowTiedRadone BowTiedRadone commented Apr 14, 2026

Clarity smart contracts benefit from property-based testing, but setting up fast-check arbitraries that produce valid Clarity values for every parameter type (uint, principal, buffers, lists, tuples, optionals, responses, trait references) is tedious and error-prone. Rendezvous already solves this internally; this PR exposes that capability as a library API so the community can use it off-the-shelf.

Two new exports:

  • getContractFunction(simnet, contract, fn, deployer?): extracts a function interface from a deployed contract, enriched with trait data
  • generateArgs(simnet, fn): returns fc.Arbitrary<ClarityValue[]>, handling all Clarity types including recursive structures (list of tuples, optional of response, etc.) and trait reference resolution

The package now works as both a CLI (npx rv) and a library (import { generateArgs } from "@stacks/rendezvous"). TypeScript declarations are included.

Fixes #168.

@BowTiedRadone
Copy link
Copy Markdown
Contributor Author

@moodmosaic @hugo-stacks @wileyj If you have bandwidth, this is a pretty small PR that should have a high effect in sustaining Clarity property-based testing efforts.

friedger
friedger previously approved these changes Apr 21, 2026
Copy link
Copy Markdown
Collaborator

@friedger friedger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, nice addition!

Copy link
Copy Markdown
Collaborator

@moodmosaic moodmosaic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BowTiedRadone shouldn't the CLI consume lib.ts as well?

@BowTiedRadone
Copy link
Copy Markdown
Contributor Author

@moodmosaic Thought about it initially, but the CLI and lib.ts are siblings, not stacked.

Two blockers:

  1. The CLI logs the raw generated args. strategyFor only returns the CV-mapped version.
  2. The CLI handles sets of functions (SUT, invariant, test, discard). getContractFunction is single-function and re-reads interfaces each call.

Making the CLI use lib.ts would either break the log output or bloat lib.ts with CLI-only logic. The shared primitives are the single source of truth, both layers sitting on top.

@moodmosaic
Copy link
Copy Markdown
Collaborator

moodmosaic commented Apr 21, 2026

Can you either:

  1. Refactor the CLI to consume getContractFunction / strategyFor (even if the CLI keeps its own thin wrapper for logging and batch orchestration), or
  2. If (1) is genuinely out of scope right now, at minimum expand lib.tests.ts to cover the full Clarity type matrix the CLI exercises — traits, nested lists/tuples, optional-of-response, etc. — so the public surface has equivalent guarantees.

Option 1 is strongly preferred: it guarantees the library API stays honest by construction, and it's the clearest signal that the maintainers trust their own public surface.


re: the CLI handles sets of functions (SUT, invariant, test, discard)

I'd actually read this as an argument for the CLI consuming lib.ts. Batch orchestration is a natural layer above a single-function primitive, and the re-read-per-call cost is a caching concern inside getContractFunction rather than a reason for two parallel code paths.


re: would either break log output or bloat lib.ts with CLI-only logic

I don't think it has to be that binary. The shape I'd reach for is: lib.ts exposes pure primitives → CLI imports those and layers logging, batching, and discard semantics on top. Nothing CLI-specific needs to migrate into lib.ts.


re: the CLI logs raw generated args, strategyFor only returns the CV-mapped version

That's a presentation concern, not an architectural one: the raw form can be surfaced via an optional return shape or debug hook, and different logging shouldn't justify a forked generation pipeline.


To be clear: I don't want to hold or block this PR — these are just my thoughts since I was pinged in as a reviewer, and you all are closer to the day-to-day tradeoffs than I am now.

`strategyFor` now accepts optional `allAddresses` and
`projectTraitImplementations` parameters. When omitted it still
derives both from the simnet, preserving the default API. Callers
that already hold a filtered account list or a precomputed trait map
can pass them through to avoid redundant work and, more importantly,
to honor user-supplied account filtering.
@BowTiedRadone
Copy link
Copy Markdown
Contributor Author

@moodmosaic Checked again and your suggestion proved to be the most friendly in the eventuality we decide to support additional features such as customizable generators, etc. Now CLI uses lib.ts methods.

@BowTiedRadone BowTiedRadone merged commit 962d53e into master Apr 22, 2026
18 checks passed
@BowTiedRadone BowTiedRadone deleted the lib/simnet-pbt branch April 22, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export random argument generation and ClarityValue conversion

3 participants