Skip to content

[Go] Add test coverage for the rand package#427

Open
tauptlab wants to merge 1 commit into
google:mainfrom
tauptlab:main
Open

[Go] Add test coverage for the rand package#427
tauptlab wants to merge 1 commit into
google:mainfrom
tauptlab:main

Conversation

@tauptlab

@tauptlab tauptlab commented May 20, 2026

Copy link
Copy Markdown

Closes the TODO at the top of rand.go asking for test coverage of the exported noise-generating functions. The package only had a test for Boolean's bit-shifting before this.

The tests are in three layers:

  • Byte-stream tests swap randBuf for a bytes.NewReader and check exact outputs. The targeted edge cases live here: I63n's rejection loop at (MaxInt64/n)*n, the sign-bit mask, Geometric's leading-zero counting, and Uniform's r==0 fallback. The fallback can't be reached from crypto/rand at any realistic call count, but it is reachable by feeding 128 zero bytes (forces Geometric() >= 1024 so math.Pow(2,k) overflows to +Inf).
  • Range tests verify that outputs sit in the documented range, 10k samples each.
  • Moment tests sample 1M times and compare mean and variance against population values, with 5-sigma tolerances derived from each distribution's variance and 4th central moment. The helper skips the variance check on Bernoulli-shaped distributions where mu_4 == sigma^4.

TestNormal_FourthMoment is a separate explicit check because Normal and Laplace at the same variance both pass the regular moment test - they only differ at mu_4 (3 vs 6). The library uses both for the Gaussian and Laplace mechanisms.

TestConcurrent stresses the package locks with 8 goroutines, plus a Boolean mean check so it has signal even without -race. testing.Short() skips the moment tests.

rand.go

  • Dropped the test-coverage TODO.
  • Added a one-line comment above randBuf saying it must wrap crypto/rand.

Two pre-existing edge cases noticed while writing the tests:

  1. I63n doesn't validate n. n=0 panics with divide-by-zero, n<0 returns values in [0, |n|) instead of failing. Added a TODO; I'll send a follow-up PR.
  2. randSource.Int63 returns math.MinInt64 once per 2^64 calls on the byte stream 0x8000000000000000 (since -math.MinInt64 == math.MinInt64 in two's complement). Added a Note in code rather than fixing - any fix would change the output mapping for ~half of all byte sequences, which seems disproportionate for a 2^-64 contract violation that's never been observed.

Testing

  • go test ./go/... clean.
  • -count=10 clean.
  • -short correctly skips the moment tests.
  • Couldn't run -race locally - no gcc on this Windows machine.

Closes the TODO that asked for tests of the exported noise-generating
functions. Includes deterministic byte-level tests, range invariants,
5-sigma moment checks, and a concurrent stress test.

Also surfaces two pre-existing edge cases while writing tests. I63n
doesn't validate non-positive n - will fix in a follow-up.
randSource.Int63 returns a negative value once per 2^64 calls on byte
stream 0x8000_0000_0000_0000 - documented as a Note since any fix
changes the output mapping for many byte sequences.
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.

1 participant