mirror of
https://github.com/google/uuid.git
synced 2024-11-24 08:32:23 +02:00
reused version4 NewRandom() and added better testing
This commit is contained in:
parent
caad4a1123
commit
63b66ddfe0
@ -5,10 +5,18 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A UuidSource holds a random number generator and generates UUIDs using it as its source.
|
||||||
|
//
|
||||||
|
// It is useful when a process need its own random number generator,
|
||||||
|
// e.g. when running some processes concurrently.
|
||||||
type UuidSource struct {
|
type UuidSource struct {
|
||||||
rander io.Reader
|
rander io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a new UuidSource which holds its own random number generator.
|
||||||
|
//
|
||||||
|
// Calling NewSource with nil sets the random number generator to a default
|
||||||
|
// generator.
|
||||||
func NewSource(r io.Reader) UuidSource {
|
func NewSource(r io.Reader) UuidSource {
|
||||||
var uuidSource UuidSource
|
var uuidSource UuidSource
|
||||||
uuidSource.SetRand(r)
|
uuidSource.SetRand(r)
|
||||||
@ -16,6 +24,12 @@ func NewSource(r io.Reader) UuidSource {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRand sets the random number generator of the UuidSource to r, which implements io.Reader.
|
||||||
|
// If r.Read returns an error when the package requests random data then
|
||||||
|
// a panic will be issued.
|
||||||
|
//
|
||||||
|
// Calling SetRand with nil sets the random number generator to a default
|
||||||
|
// generator.
|
||||||
func (uuidSource *UuidSource) SetRand(r io.Reader) {
|
func (uuidSource *UuidSource) SetRand(r io.Reader) {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
uuidSource.rander = rand.Reader
|
uuidSource.rander = rand.Reader
|
||||||
@ -24,17 +38,17 @@ func (uuidSource *UuidSource) SetRand(r io.Reader) {
|
|||||||
uuidSource.rander = r
|
uuidSource.rander = r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewRandom returns a Random (Version 4) UUID based on the random number generator in the UuidSource.
|
||||||
|
//
|
||||||
|
// See more detailed explanation here: https://godoc.org/github.com/google/uuid#NewRandom
|
||||||
func (uuidSource UuidSource) NewRandom() (UUID, error) {
|
func (uuidSource UuidSource) NewRandom() (UUID, error) {
|
||||||
var uuid UUID
|
return newRandom(uuidSource.rander)
|
||||||
_, err := io.ReadFull(uuidSource.rander, uuid[:])
|
|
||||||
if err != nil {
|
|
||||||
return Nil, err
|
|
||||||
}
|
|
||||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
|
||||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
|
||||||
return uuid, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New creates a new random UUID based on the random number generator in the UuidSource or panics. New is equivalent to
|
||||||
|
// the expression
|
||||||
|
//
|
||||||
|
// uuid.Must(uuid.NewRandom())
|
||||||
func (uuidSource UuidSource) New() UUID {
|
func (uuidSource UuidSource) New() UUID {
|
||||||
return Must(uuidSource.NewRandom())
|
return Must(uuidSource.NewRandom())
|
||||||
}
|
}
|
||||||
|
@ -7,23 +7,53 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestUuidSources(t *testing.T) {
|
func TestUuidSources(t *testing.T) {
|
||||||
|
|
||||||
|
// Two identical sources, should give same sequence
|
||||||
currentTime := time.Now().UnixNano()
|
currentTime := time.Now().UnixNano()
|
||||||
uuidSourceA := NewSource(rand.New(rand.NewSource(currentTime)))
|
uuidSourceA := NewSource(rand.New(rand.NewSource(currentTime)))
|
||||||
uuidSourceB := NewSource(rand.New(rand.NewSource(currentTime)))
|
uuidSourceB := NewSource(rand.New(rand.NewSource(currentTime)))
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
if uuidSourceA.New().String() != uuidSourceB.New().String() {
|
uuid1 := uuidSourceA.New()
|
||||||
t.Error("Uuid values are not reproducaible!")
|
uuid2 := uuidSourceB.New()
|
||||||
|
if uuid1 != uuid2 {
|
||||||
|
t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uuidSourceA = NewSource(rand.New(rand.NewSource(123)))
|
// Set rander with nil, each source will be random
|
||||||
uuidSourceB = NewSource(rand.New(rand.NewSource(456)))
|
uuidSourceA.SetRand(nil)
|
||||||
|
uuidSourceB.SetRand(nil)
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
if uuidSourceA.New().String() == uuidSourceB.New().String() {
|
uuid1 := uuidSourceA.New()
|
||||||
t.Error("Uuid values should not match!")
|
uuid2 := uuidSourceB.New()
|
||||||
|
if uuid1 == uuid2 {
|
||||||
|
t.Errorf("unexpected duplicates, got %q", uuid1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set rander to rand source with same seed, should give same sequence
|
||||||
|
uuidSourceA.SetRand(rand.New(rand.NewSource(123)))
|
||||||
|
uuidSourceB.SetRand(rand.New(rand.NewSource(123)))
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
uuid1 := uuidSourceA.New()
|
||||||
|
uuid2 := uuidSourceB.New()
|
||||||
|
if uuid1 != uuid2 {
|
||||||
|
t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set rander to rand source with different seeds, should not give same sequence
|
||||||
|
uuidSourceA.SetRand(rand.New(rand.NewSource(456)))
|
||||||
|
uuidSourceB.SetRand(rand.New(rand.NewSource(789)))
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
uuid1 := uuidSourceA.New()
|
||||||
|
uuid2 := uuidSourceB.New()
|
||||||
|
if uuid1 == uuid2 {
|
||||||
|
t.Errorf("unexpected duplicates, got %q", uuid1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
uuid_test.go
21
uuid_test.go
@ -13,6 +13,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
@ -479,6 +481,25 @@ func TestBadRand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetRand(t *testing.T) {
|
||||||
|
SetRand(rand.New(rand.NewSource(456)))
|
||||||
|
uuid1 := New()
|
||||||
|
uuid2 := New()
|
||||||
|
|
||||||
|
SetRand(rand.New(rand.NewSource(456)))
|
||||||
|
uuid3 := New()
|
||||||
|
uuid4 := New()
|
||||||
|
|
||||||
|
if uuid1 != uuid3 {
|
||||||
|
t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3)
|
||||||
|
}
|
||||||
|
if uuid2 != uuid4 {
|
||||||
|
t.Errorf("expected duplicates, got %q and %q", uuid2, uuid4)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
|
var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
|
||||||
var asBytes = []byte(asString)
|
var asBytes = []byte(asString)
|
||||||
|
|
||||||
|
@ -27,8 +27,12 @@ func New() UUID {
|
|||||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||||
// year and having one duplicate.
|
// year and having one duplicate.
|
||||||
func NewRandom() (UUID, error) {
|
func NewRandom() (UUID, error) {
|
||||||
|
return newRandom(rander)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRandom(r io.Reader) (UUID, error) {
|
||||||
var uuid UUID
|
var uuid UUID
|
||||||
_, err := io.ReadFull(rander, uuid[:])
|
_, err := io.ReadFull(r, uuid[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Nil, err
|
return Nil, err
|
||||||
}
|
}
|
||||||
@ -36,3 +40,4 @@ func NewRandom() (UUID, error) {
|
|||||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
return uuid, nil
|
return uuid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user