Skip to content
This repository has been archived by the owner on Jan 10, 2024. It is now read-only.

Commit

Permalink
Fix charRange to allow picking the last item (#36)
Browse files Browse the repository at this point in the history
* Add test proving charRange.choose excludes the last item

Change charRange#choose to accept an interface, int63nPicker, exposing only
Int63n(int64) int64. This allows the test to pass a custom RNG, returning a
constant value (0 or the last possible int).

Change charRange#choose to act on an immutable copy of charRange.

* Allow charRange.choose to pick the last rune

Before this change, choose would never pick the last character of the set. This
is not the expected behavior: if the range is a-z, we expect a,b,...,y,z to be
picked in a uniform way.
  • Loading branch information
punkeel authored Feb 10, 2020
1 parent 2257016 commit 1868c06
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
10 changes: 7 additions & 3 deletions fuzz.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,15 +471,19 @@ func randBool(r *rand.Rand) bool {
return false
}

type int63nPicker interface {
Int63n(int64) int64
}

type charRange struct {
first, last rune
}

// choose returns a random unicode character from the given range, using the
// given randomness source.
func (r *charRange) choose(rand *rand.Rand) rune {
count := int64(r.last - r.first)
return r.first + rune(rand.Int63n(count))
func (cr charRange) choose(r int63nPicker) rune {
count := int64(cr.last - cr.first + 1)
return cr.first + rune(r.Int63n(count))
}

var unicodeRanges = []charRange{
Expand Down
41 changes: 41 additions & 0 deletions fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package fuzz

import (
"math/rand"
"reflect"
"regexp"
"testing"
Expand Down Expand Up @@ -512,3 +513,43 @@ func TestFuzz_SkipPattern(t *testing.T) {
return 5, true
})
}

type int63mode int

const (
modeRandom int63mode = iota
modeFirst
modeLast
)

type customInt63 struct {
mode int63mode
}

func (c customInt63) Int63n(n int64) int64 {
switch c.mode {
case modeFirst: return 0
case modeLast: return n-1
default: return rand.Int63n(n)
}
}

func Test_charRange_choose(t *testing.T) {
lowercaseLetters := charRange{'a', 'z'}

t.Run("Picks first", func(t *testing.T) {
r := customInt63{mode: modeFirst}
letter := lowercaseLetters.choose(r)
if letter != 'a' {
t.Errorf("Expected a, got %v", letter)
}
})

t.Run("Picks last", func(t *testing.T) {
r := customInt63{mode: modeLast}
letter := lowercaseLetters.choose(r)
if letter != 'z' {
t.Errorf("Expected z, got %v", letter)
}
})
}

0 comments on commit 1868c06

Please sign in to comment.