rclone/vendor/github.com/marstr/guid/guid_test.go
2018-01-16 13:20:59 +00:00

370 lines
8 KiB
Go

package guid
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"testing"
)
func Test_DefaultIsVersion4(t *testing.T) {
subject := NewGUID()
if ver := subject.Version(); ver != 4 {
t.Logf("Default GUID should be produced using algorithm: version 4. Actual: version %d\n%s", ver, subject.String())
t.Fail()
}
}
func Test_NewGUIDs_NotEmpty(t *testing.T) {
for strat := range knownStrategies {
t.Run(string(strat), func(subT *testing.T) {
subject, err := NewGUIDs(strat)
if err != nil {
subT.Error(err)
}
if subject == Empty() {
subT.Logf("unexpected empty encountered")
subT.Fail()
}
})
}
}
func Test_NewGUIDs_Unsupported(t *testing.T) {
fauxStrategy := CreationStrategy("invalidStrategy")
subject, err := NewGUIDs(fauxStrategy)
if subject != Empty() {
t.Fail()
}
if err.Error() != "Unsupported CreationStrategy" {
t.Fail()
}
}
func Test_Format_Empty(t *testing.T) {
subject := Empty()
testCases := []struct {
shortFormat Format
expected string
}{
{FormatP, "(00000000-0000-0000-0000-000000000000)"},
{FormatX, "{0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}"},
{FormatN, "00000000000000000000000000000000"},
{FormatD, "00000000-0000-0000-0000-000000000000"},
{FormatB, "{00000000-0000-0000-0000-000000000000}"},
}
for _, scenario := range testCases {
t.Run("", func(subT *testing.T) {
result := subject.Stringf(scenario.shortFormat)
if result != scenario.expected {
subT.Logf("\nwant:\t%s\ngot: \t%s", scenario.expected, result)
subT.Fail()
}
})
}
}
func Test_Parse_Roundtrip(t *testing.T) {
subject := NewGUID()
for format := range knownFormats {
t.Run(string(format), func(subT *testing.T) {
serialized := subject.Stringf(format)
parsed, parseErr := Parse(serialized)
if nil != parseErr {
subT.Error(parseErr)
}
if parsed != subject {
subT.Logf("\nwant:\t%s\ngot: \t%s", subject.String(), parsed.String())
subT.Fail()
}
})
}
}
func Test_Parse_Failures(t *testing.T) {
testCases := []string{
"",
"abc",
"00000000-0000-0000-0000-000000", // Missing digits
}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
result, err := Parse(tc)
if expected := fmt.Sprintf(`"%s" is not in a recognized format`, tc); nil == err || expected != err.Error() {
t.Logf("\nwant:\t%s\ngot: \t%v", expected, err)
t.Fail()
}
if result != Empty() {
t.Logf("\nwant:\t%s\ngot: \t%s", Empty().String(), result.String())
t.Fail()
}
})
}
}
func Test_version4_ReservedBits(t *testing.T) {
for i := 0; i < 500; i++ {
result, _ := version4()
if result.clockSeqHighAndReserved&0xc0 != 0x80 {
t.Fail()
}
}
}
func TestGUID_Stringf(t *testing.T) {
rand := NewGUID()
formats := []Format{Format("")}
for format := range knownFormats {
formats = append(formats, format)
}
for _, format := range formats {
t.Run(string(format), func(t *testing.T) {
result := rand.Stringf(format)
if result == "" {
t.Logf("could not create string for format, '%s'", string(format))
t.FailNow()
}
rehydrated, err := Parse(result)
if err != nil {
t.Error(err)
}
if rehydrated != rand {
t.Logf("'%s' isn't well formed", result)
t.Fail()
}
})
}
}
func Test_version4_NoOctetisReliablyZero(t *testing.T) {
results := make(map[string]uint)
const iterations uint = 500
const suspicionThreshold uint = iterations / 10
results["time_low"] = 0
results["time_mid"] = 0
results["time_hi_and_version"] = 0
results["clock_seq_hi_and_reserved"] = 0
results["clock_seq_low"] = 0
results["node"] = 0
for i := uint(0); i < iterations; i++ {
current, _ := version4()
if 0 == current.timeLow {
results["time_low"]++
}
if 0 == current.timeMid {
results["time_mid"]++
}
if 0 == current.timeHighAndVersion {
results["time_hi_and_version"]++
}
if 0 == current.clockSeqHighAndReserved {
results["clock_seq_hi_and_reserved"]++
}
if 0 == current.clockSeqLow {
results["clock_seq_low"]++
}
}
anySuspicious := false
for key, val := range results {
if val > suspicionThreshold {
anySuspicious = true
t.Logf("%s reported value 0 enough times (%d of %d) to be suspicious.", key, val, iterations)
}
}
if anySuspicious {
t.Fail()
}
}
func Test_SubsequentCallsDiffer(t *testing.T) {
for strat := range knownStrategies {
t.Run(string(strat), func(subT *testing.T) {
seen := make(map[GUID]struct{})
for i := 0; i < 500; i++ {
result, err := NewGUIDs(strat)
if err != nil {
subT.Error(err)
}
if _, present := seen[result]; present == true {
subT.Logf("The value %s was generated multiple times.", result.String())
subT.Fail()
}
seen[result] = struct{}{}
}
})
}
}
func Test_JSONRoundTrip(t *testing.T) {
testCases := []GUID{
Empty(),
NewGUID(),
}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
marshaled, err := json.Marshal(tc)
if err != nil {
t.Error(err)
}
var unmarshaled GUID
err = json.Unmarshal(marshaled, &unmarshaled)
if err != nil {
t.Error(err)
}
if tc != unmarshaled {
t.Logf("\ngot: \t%s\nwant:\t%s", unmarshaled.String(), tc.String())
t.Fail()
}
})
}
}
func TestGUID_UnmarshalJSON_Failure(t *testing.T) {
invalidJSON := errors.New("unexpected end of JSON input")
notJSONString := errors.New("JSON GUID must be surrounded by quotes")
testCases := []struct {
string
error
}{
{``, invalidJSON},
{`"`, invalidJSON},
{`a`, errors.New("invalid character 'a' looking for beginning of value")},
{`3`, notJSONString},
{`""`, errors.New(`"" is not in a recognized format`)},
{`"ab"`, errors.New(`"ab" is not in a recognized format`)},
}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
var unmarshaled GUID
err := json.Unmarshal([]byte(tc.string), &unmarshaled).Error()
if expected := tc.error.Error(); err != expected {
t.Logf("\ngot: \t%s\nwant:\t%s", err, expected)
t.Fail()
}
if expected := Empty(); unmarshaled != expected {
t.Logf("\ngot: \t%s\nwant:\t%s", unmarshaled.String(), expected.String())
t.Fail()
}
})
}
}
func Test_getMACAddress(t *testing.T) {
subject, err := getMACAddress()
t.Logf("MAC returned: %02x:%02x:%02x:%02x:%02x:%02x", subject[0], subject[1], subject[2], subject[3], subject[4], subject[5])
if nil != err {
t.Error(err)
}
nonZeroSeen := false
for _, octet := range subject {
if 0 != octet {
nonZeroSeen = true
break
}
}
if !nonZeroSeen {
t.Fail()
}
}
func Test_setVersion_bounds(t *testing.T) {
testCases := []uint16{0, 6}
for _, tc := range testCases {
t.Run(fmt.Sprint(tc), func(t *testing.T) {
var fodder GUID
err := fodder.setVersion(tc)
if nil == err {
t.Log("error expected but unfound when version set to 0")
t.Fail()
}
})
}
}
func Benchmark_NewGUIDs(b *testing.B) {
for strat := range knownStrategies {
b.Run(string(strat), func(b *testing.B) {
for i := 0; i < b.N; i++ {
NewGUIDs(strat)
}
})
}
}
func Benchmark_String(b *testing.B) {
rand, _ := NewGUIDs(CreationStrategyVersion4)
b.ResetTimer()
for i := 0; i < b.N; i++ {
fmt.Fprint(ioutil.Discard, rand.String()) // This slows down the call, but lets `go vet` pass.
}
}
func Benchmark_Stringf(b *testing.B) {
rand := NewGUID()
b.ResetTimer()
for format := range knownFormats {
b.Run(string(format), func(b *testing.B) {
for i := 0; i < b.N; i++ {
rand.Stringf(format)
}
})
}
}
func Benchmark_Parse(b *testing.B) {
rand := NewGUID()
b.ResetTimer()
for format := range knownFormats {
printed := rand.Stringf(format)
b.Run(string(format), func(b *testing.B) {
for i := 0; i < b.N; i++ {
Parse(printed)
}
})
}
}
func ExampleGUID_Stringf() {
fmt.Printf(Empty().Stringf(FormatB))
// Output: {00000000-0000-0000-0000-000000000000}
}
func ExampleGUID_String() {
fmt.Printf(Empty().String())
// Output: 00000000-0000-0000-0000-000000000000
}
func ExampleEmpty() {
var example GUID
if example == Empty() {
fmt.Print("Example is Empty")
} else {
fmt.Print("Example is not Empty")
}
// Output: Example is Empty
}