Skip to content

Commit

Permalink
test/mock: implement mock for crypto [rand.Reader]
Browse files Browse the repository at this point in the history
The RandReader implement [io.Reader].
To provide predictable result, the RandReader is seeded with slice of
bytes.
A call to Read will fill the passed bytes with those seed.

For example, given seed as "abc" (length is three), calling Read with
bytes length five will return "abcab".
  • Loading branch information
shuLhan committed Jan 28, 2024
1 parent 137d874 commit e33a335
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/test/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.

// Package mock provide a mocking for standard input, standard output,
// standard error, and io.ReadWriter.
// standard error, io.ReadWriter, and [rand.Reader].
package mock

import (
Expand Down
51 changes: 51 additions & 0 deletions lib/test/mock/rand_reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2024, Shulhan <[email protected]>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mock

// RandReader implement [io.Reader] for mocking crypto [rand.Reader].
// To provide predictable result, the RandReader is seeded with the same
// slice of bytes.
// A call to Read will fill the passed bytes with those seed.
type RandReader struct {
seed []byte
counter int
}

// NewRandReader create new random reader using seed as generator.
// The longer the seed, the longer the random values become unique.
func NewRandReader(seed []byte) (r *RandReader) {
r = &RandReader{
seed: seed,
}
return r
}

// Read fill the raw bytes with seed.
// If raw length larger than the seed, it will be filled with the same seed
// until all bytes filled.
//
// For example, given seed as "abc" (length is three), and raw length is
// five, then Read will return "abcab".
func (rr *RandReader) Read(raw []byte) (n int, err error) {
var (
expn = len(raw)

nwrite int
)

for n < expn {
nwrite = copy(raw[n:], rr.seed[rr.counter:])
n += nwrite
}

// Increment the counter to make the seed start from next byte, so
// the next Read will return different result but still predictable.
rr.counter++
if rr.counter == len(rr.seed) {
rr.counter = 0
}

return n, nil
}
41 changes: 41 additions & 0 deletions lib/test/mock/rand_reader_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2024, Shulhan <[email protected]>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mock_test

import (
"crypto/rand"
"fmt"
"log"

"github.com/shuLhan/share/lib/test/mock"
)

func ExampleRandReader() {
var (
seed = []byte(`123`)
rr = mock.NewRandReader(seed)
b = make([]byte, 8)

x int
n int
err error
)

rand.Reader = rr

for x = 0; x <= len(seed); x++ {
n, err = rand.Read(b)
if err != nil {
log.Fatal(err)
}
fmt.Println(n, string(b))
}

// Output:
// 8 12312312
// 8 23232323
// 8 33333333
// 8 12312312
}

0 comments on commit e33a335

Please sign in to comment.