Etymon.Invariants.FsCheck
0.1.0-preview.13
dotnet add package Etymon.Invariants.FsCheck --version 0.1.0-preview.13
NuGet\Install-Package Etymon.Invariants.FsCheck -Version 0.1.0-preview.13
<PackageReference Include="Etymon.Invariants.FsCheck" Version="0.1.0-preview.13" />
<PackageVersion Include="Etymon.Invariants.FsCheck" Version="0.1.0-preview.13" />
<PackageReference Include="Etymon.Invariants.FsCheck" />
paket add Etymon.Invariants.FsCheck --version 0.1.0-preview.13
#r "nuget: Etymon.Invariants.FsCheck, 0.1.0-preview.13"
#:package Etymon.Invariants.FsCheck@0.1.0-preview.13
#addin nuget:?package=Etymon.Invariants.FsCheck&version=0.1.0-preview.13&prerelease
#tool nuget:?package=Etymon.Invariants.FsCheck&version=0.1.0-preview.13&prerelease
Etymon.Invariants.FsCheck
FsCheck generators that produce only values your schema accepts — and values it should reject, for testing that it does.
Part of the Etymon suite. Depends on
Etymon.Core, Etymon.Schema, Etymon.Invariants and FsCheck.
Generate.valid personSchema // Gen<Person>, all of them decodable
Generate.arbitrary personSchema // the same, as an Arbitrary
Generate.invalid personSchema // values that should be rejected, and where
Generate.validSatisfying invariants bookingSchema // legal bookings, not merely decodable ones
How a value is known to be valid
Values are generated as JSON and decoded through the schema itself, rather than constructed directly. That reuses the decoder — already the most heavily tested code in the suite — instead of adding a second construction path that could drift away from it. A generated value is valid by exactly the definition production code uses.
Constraints are satisfied constructively wherever Etymon understands them: a
length bound picks a string of that length, a range picks a number inside it, an
enumeration picks a member, Format.Email builds something with an @ and a dot
rather than hoping.
It fails loudly rather than quietly
Some rules can only be filtered for — a regular expression, an Opaque
predicate, a cross-field invariant. Where filtering runs out of budget, this
raises GenerationFailed with the rule's name and what to do about it.
That is deliberate. The normal behaviour of a filtered generator is to discard and carry on, so a property test that should have run a hundred cases runs eleven, passes, and tells you so confidently. A loud failure is worth much more than a thin sample.
Could not generate a value of Booking satisfying its invariants
(endDate-after-startDate) in 500 attempts. Cross-field rules usually cannot be
satisfied by chance; supply a generator that constructs valid values directly.
The same applies to a recursive schema, which has no fixed point a generator can reach, and to an unsatisfiable constraint like a range whose floor is above its ceiling.
Negative testing that checks more than "it failed"
Generate.invalid produces values the schema should reject, each carrying what
is wrong with it and where the error should land:
{ Description = "the required field 'email' removed"
Json = """{"tags":[]}"""
ExpectedPath = "email"
ExpectedReason = ErrorReason.Missing }
Asserting only that decoding failed would pass just as well when it failed for the wrong reason. Checking the path is what makes the assertion worth making.
Ready-made properties
testProperty "Person round-trips" (fun () -> Properties.roundTrips Person.schema)
testProperty "encoding is stable" (fun () -> Properties.isDeterministic Person.schema)
testProperty "bad input is rejected" (fun () -> Properties.invalidIsRejected Person.schema)
testProperty "everything at once" (fun () -> Properties.all Person.schema)
testProperty "generated bookings are legal" (fun () ->
Properties.generatedValuesSatisfy Booking.invariants Booking.schema)
generatedValuesSatisfy is the one that earns its keep. A failure means the
schema is looser than the type: something the decoder lets through is not a
legal value, which is precisely the gap a smart constructor exists to close.
Public surface
The complete public surface of this package, every value with its full signature
and its documentation, is in Surface.fsi beside this file. It is written by the
build from the implementation, so it is where to learn what a function hands
back without compiling anything.
Licence
MIT.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Etymon.Core (>= 0.1.0-preview.13)
- Etymon.Invariants (>= 0.1.0-preview.13)
- Etymon.Schema (>= 0.1.0-preview.13)
- FsCheck (>= 3.4.0)
- FSharp.Core (>= 8.0.100)
-
net8.0
- Etymon.Core (>= 0.1.0-preview.13)
- Etymon.Invariants (>= 0.1.0-preview.13)
- Etymon.Schema (>= 0.1.0-preview.13)
- FsCheck (>= 3.4.0)
- FSharp.Core (>= 8.0.100)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-preview.13 | 24 | 9/22/2026 |
| 0.1.0-preview.12 | 22 | 9/22/2026 |
| 0.1.0-preview.11 | 22 | 9/22/2026 |
| 0.1.0-preview.10 | 29 | 9/22/2026 |
| 0.1.0-preview.9 | 39 | 9/22/2026 |
| 0.1.0-preview.8 | 29 | 9/22/2026 |
| 0.1.0-preview.7 | 43 | 9/21/2026 |
| 0.1.0-preview.6 | 34 | 9/21/2026 |
| 0.1.0-preview.5 | 34 | 9/21/2026 |
| 0.1.0-preview.4 | 42 | 9/21/2026 |
| 0.1.0-preview.3 | 47 | 9/21/2026 |
| 0.1.0-preview.2 | 47 | 9/20/2026 |
| 0.1.0-preview.1 | 44 | 9/20/2026 |