pgregory.net/rand@v1.0.3-0.20230808192358-a0b8ce02f4da/rand_test.go (about)

     1  // Copyright 2022 Gregory Petrosyan <gregory.petrosyan@gmail.com>
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, v. 2.0. If a copy of the MPL was not distributed with this
     5  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
     6  
     7  package rand_test
     8  
     9  import (
    10  	"bytes"
    11  	"math"
    12  	"math/bits"
    13  	"pgregory.net/rand"
    14  	"pgregory.net/rapid"
    15  	"testing"
    16  )
    17  
    18  func TestRand_Read(t *testing.T) {
    19  	rapid.Check(t, func(t *rapid.T) {
    20  		const N = 32
    21  		s := rapid.Uint64().Draw(t, "s").(uint64)
    22  		r := rand.New(s)
    23  		buf := make([]byte, N)
    24  		_, _ = r.Read(buf)
    25  		r.Seed(s)
    26  		buf2 := make([]byte, N)
    27  		for n := 0; n < N; {
    28  			c := rapid.IntRange(0, N-n).Draw(t, "c").(int)
    29  			_, _ = r.Read(buf2[n : n+c])
    30  			n += c
    31  		}
    32  		if !bytes.Equal(buf, buf2) {
    33  			t.Fatalf("got %q instead of %q when reading in chunks", buf2, buf)
    34  		}
    35  	})
    36  }
    37  
    38  func TestRand_Float32(t *testing.T) {
    39  	rapid.Check(t, func(t *rapid.T) {
    40  		s := rapid.Uint64().Draw(t, "s").(uint64)
    41  		r := rand.New(s)
    42  		f := r.Float32()
    43  		if f < 0 || f >= 1 {
    44  			t.Fatalf("got %v outside of [0, 1)", f)
    45  		}
    46  	})
    47  }
    48  
    49  func TestRand_Float64(t *testing.T) {
    50  	rapid.Check(t, func(t *rapid.T) {
    51  		s := rapid.Uint64().Draw(t, "s").(uint64)
    52  		r := rand.New(s)
    53  		f := r.Float64()
    54  		if f < 0 || f >= 1 {
    55  			t.Fatalf("got %v outside of [0, 1)", f)
    56  		}
    57  	})
    58  }
    59  
    60  func TestRand_Int31n(t *testing.T) {
    61  	rapid.Check(t, func(t *rapid.T) {
    62  		s := rapid.Uint64().Draw(t, "s").(uint64)
    63  		r := rand.New(s)
    64  		n := rapid.Int32Range(1, math.MaxInt32).Draw(t, "n").(int32)
    65  		v := r.Int31n(n)
    66  		if v < 0 || v >= n {
    67  			t.Fatalf("got %v outside of [0, %v)", v, n)
    68  		}
    69  	})
    70  }
    71  
    72  func TestRand_Int63n(t *testing.T) {
    73  	rapid.Check(t, func(t *rapid.T) {
    74  		s := rapid.Uint64().Draw(t, "s").(uint64)
    75  		r := rand.New(s)
    76  		n := rapid.Int64Range(1, math.MaxInt64).Draw(t, "n").(int64)
    77  		v := r.Int63n(n)
    78  		if v < 0 || v >= n {
    79  			t.Fatalf("got %v outside of [0, %v)", v, n)
    80  		}
    81  	})
    82  }
    83  
    84  func TestRand_Intn(t *testing.T) {
    85  	rapid.Check(t, func(t *rapid.T) {
    86  		s := rapid.Uint64().Draw(t, "s").(uint64)
    87  		r := rand.New(s)
    88  		n := rapid.IntRange(1, math.MaxInt).Draw(t, "n").(int)
    89  		v := r.Intn(n)
    90  		if v < 0 || v >= n {
    91  			t.Fatalf("got %v outside of [0, %v)", v, n)
    92  		}
    93  	})
    94  }
    95  
    96  func TestRand_Uint32n(t *testing.T) {
    97  	rapid.Check(t, func(t *rapid.T) {
    98  		s := rapid.Uint64().Draw(t, "s").(uint64)
    99  		r := rand.New(s)
   100  		n := rapid.Uint32Range(1, math.MaxUint32).Draw(t, "n").(uint32)
   101  		v := r.Uint32n(n)
   102  		if v >= n {
   103  			t.Fatalf("got %v outside of [0, %v)", v, n)
   104  		}
   105  	})
   106  }
   107  
   108  func TestRand_Uint64n(t *testing.T) {
   109  	rapid.Check(t, func(t *rapid.T) {
   110  		s := rapid.Uint64().Draw(t, "s").(uint64)
   111  		r := rand.New(s)
   112  		n := rapid.Uint64Range(1, math.MaxUint64).Draw(t, "n").(uint64)
   113  		v := r.Uint64n(n)
   114  		if v >= n {
   115  			t.Fatalf("got %v outside of [0, %v)", v, n)
   116  		}
   117  	})
   118  }
   119  
   120  func TestRand_MarshalBinary_Roundtrip(t *testing.T) {
   121  	rapid.Check(t, func(t *rapid.T) {
   122  		s := rapid.Uint64().Draw(t, "s").(uint64)
   123  		r1 := rand.New(s)
   124  		data1, err := r1.MarshalBinary()
   125  		if err != nil {
   126  			t.Fatalf("got unexpected marshal error: %v", err)
   127  		}
   128  		var r2 rand.Rand
   129  		err = r2.UnmarshalBinary(data1)
   130  		if err != nil {
   131  			t.Fatalf("got unexpected unmarshal error: %v", err)
   132  		}
   133  		data2, err := r2.MarshalBinary()
   134  		if err != nil {
   135  			t.Fatalf("got unexpected marshal error: %v", err)
   136  		}
   137  		if !bytes.Equal(data1, data2) {
   138  			t.Fatalf("data %q / %q after marshal/unmarshal", data1, data2)
   139  		}
   140  	})
   141  }
   142  
   143  func TestRand_Uint32nOpt(t *testing.T) {
   144  	rapid.Check(t, func(t *rapid.T) {
   145  		n := rapid.Uint32().Draw(t, "n").(uint32)
   146  		v := rapid.Uint64().Draw(t, "v").(uint64)
   147  
   148  		res, frac := bits.Mul32(n, uint32(v>>32))
   149  		hi, _ := bits.Mul32(n, uint32(v))
   150  		_, carry := bits.Add32(frac, hi, 0)
   151  		res += carry
   152  
   153  		res2, _ := bits.Mul64(uint64(n), v)
   154  
   155  		if uint32(res2) != res {
   156  			t.Fatalf("got %v instead of %v", res2, res)
   157  		}
   158  	})
   159  }