Property-based testing for Go using group theory
Make mathematical properties (associativity, commutativity, identity, inverse, closure) easy to test in Go code.
For complex types, use the fluent Laws wrapper:
func TestPacketPhysics(t *testing.T) {
law := lawtest.For(t, packetGen, packetEq)
law.Associative(add) // ✅ (a∘b)∘c = a∘(b∘c)
law.Commutative(add) // ✅ a∘b = b∘a
law.Identity(add, zero) // ✅ a∘e = a
law.Inverse(add, neg, zero) // ✅ a∘a⁻¹ = e
// Or test all group axioms at once:
law.AbelianGroup(add, neg, zero)
}Configure tests with options instead of separate functions:
lawtest.For(t, gen, eq).With(lawtest.WithTrials(500)).Associative(add)All methods return bool for early exit:
if !law.Associative(add) {
return // Stop if physics break
}Traditional unit tests check specific inputs. Property tests check rules that should always hold:
// Unit test: Does 2 + 3 = 5?
assert.Equal(t, 5, add(2, 3))
// Property test: Is addition associative for ALL numbers?
lawtest.For(t, intGen, intEq).Associative(add)The property test generates hundreds of random inputs and verifies the mathematical law holds.
go get github.com/alexshd/lawtestfunc TestIntegerAddition(t *testing.T) {
gen := func() int { return rand.Intn(200) - 100 }
eq := func(a, b int) bool { return a == b }
add := func(a, b int) int { return a + b }
neg := func(a int) int { return -a }
law := lawtest.For(t, gen, eq)
law.Group(add, neg, 0) // Tests associativity, identity, inverse
}func TestZ3VectorSpace(t *testing.T) {
vs := lawtest.ForVectorSpace(t, vecGen, scalGen, vecEq)
vs.Axioms(add, zero, neg, scale, scalarAdd, scalarMul, scalarOne)
}- Associative:
(a ∘ b) ∘ c = a ∘ (b ∘ c) - Commutative:
a ∘ b = b ∘ a - Identity:
a ∘ e = a(e is identity element) - Inverse:
a ∘ a⁻¹ = e(inverse exists) - Idempotent:
f(f(x)) = f(x) - Group: All group axioms at once
- AbelianGroup: Group + commutativity
- Immutable: Operation doesn't mutate inputs
- ParallelSafe: No race conditions
- Axioms: All 8 vector space axioms
- AssociativeCustom, CommutativeCustom, etc. for backward compatibility
- GroupCustom[T any] interface for non-comparable types
- TestGroupCustom, TestVectorSpaceCustom for interface-based testing
// Create a law checker
law := lawtest.For(t, gen, eq)
// Individual checks (all return bool)
law.Associative(op) // (a·b)·c = a·(b·c)
law.Commutative(op) // a·b = b·a
law.Identity(op, e) // a·e = a
law.Inverse(op, inv, e) // a·a⁻¹ = e
law.Idempotent(op) // f(f(x)) = f(x)
// Convenience methods
law.Group(op, inv, e) // All group axioms
law.AbelianGroup(op, inv, e) // Group + commutativity
// Concurrency tests
law.Immutable(op) // op doesn't mutate inputs
law.ParallelSafe(op, 8) // op is thread-safe
// With options
law.With(lawtest.WithTrials(500)).Associative(op)
law.With(lawtest.WithTimeout(time.Second)).Group(op, inv, e)vs := lawtest.ForVectorSpace(t, vecGen, scalGen, vecEq)
vs.Axioms(add, zero, neg, scale, sAdd, sMul, sOne)| Option | Description |
|---|---|
WithTrials(n) |
Number of random test cases (default: 100) |
WithTimeout(d) |
Timeout for all trials (default: 30s) |
For backward compatibility, these are still available:
Associative,AssociativeCustom,AssociativeWithConfigCommutative,CommutativeCustom,CommutativeWithConfigIdentity,IdentityCustomInverse,InverseCustomTestGroupCustom,TestAbelianGroupCustom,TestVectorSpaceCustom
- Go 1.18 or higher (uses generics)
- examples/interface_groups/CONCURRENCY_TESTING.md - Concurrency testing guide
Apache 2.0 - See LICENSE file for details.
Copyright 2025 Alex Shadrin (@alexshd)