diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3dd14d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# binary bundle generated by go-fuzz +uuid-fuzz.zip diff --git a/codec_test.go b/codec_test.go index 971fbbf..3f27fe0 100644 --- a/codec_test.go +++ b/codec_test.go @@ -23,246 +23,271 @@ package uuid import ( "bytes" - - . "gopkg.in/check.v1" + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" ) -type codecTestSuite struct{} - -var _ = Suite(&codecTestSuite{}) - -func (s *codecTestSuite) TestFromBytes(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - u1, err := FromBytes(b1) - c.Assert(err, IsNil) - c.Assert(u1, Equals, u) - - b2 := []byte{} - _, err = FromBytes(b2) - c.Assert(err, NotNil) +// codecTestData holds []byte data for a UUID we commonly use for testing. +var codecTestData = []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + +// codecTestUUID is the UUID value corresponding to codecTestData. +var codecTestUUID = UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + +func TestFromBytes(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + got, err := FromBytes(codecTestData) + if err != nil { + t.Fatal(err) + } + if got != codecTestUUID { + t.Fatalf("FromBytes(%x) = %v, want %v", codecTestData, got, codecTestUUID) + } + }) + t.Run("Invalid", func(t *testing.T) { + var short [][]byte + for i := 0; i < len(codecTestData); i++ { + short = append(short, codecTestData[:i]) + } + var long [][]byte + for i := 1; i < 17; i++ { + tmp := append(codecTestData, make([]byte, i)...) + long = append(long, tmp) + } + invalid := append(short, long...) + for _, b := range invalid { + got, err := FromBytes(b) + if err == nil { + t.Fatalf("FromBytes(%x): want err != nil, got %v", b, got) + } + } + }) } -func (s *codecTestSuite) BenchmarkFromBytes(c *C) { - bytes := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - for i := 0; i < c.N; i++ { - FromBytes(bytes) - } -} - -func (s *codecTestSuite) TestMarshalBinary(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} +func TestFromBytesOrNil(t *testing.T) { + t.Run("Invalid", func(t *testing.T) { + b := []byte{4, 8, 15, 16, 23, 42} + got := FromBytesOrNil(b) + if got != Nil { + t.Errorf("FromBytesOrNil(%x): got %v, want %v", b, got, Nil) + } + }) + t.Run("Valid", func(t *testing.T) { + got := FromBytesOrNil(codecTestData) + if got != codecTestUUID { + t.Errorf("FromBytesOrNil(%x): got %v, want %v", codecTestData, got, codecTestUUID) + } + }) - b2, err := u.MarshalBinary() - c.Assert(err, IsNil) - c.Assert(bytes.Equal(b1, b2), Equals, true) } -func (s *codecTestSuite) BenchmarkMarshalBinary(c *C) { - u, err := NewV4() - c.Assert(err, IsNil) - for i := 0; i < c.N; i++ { - u.MarshalBinary() - } +type fromStringTest struct { + input string + variant string } -func (s *codecTestSuite) TestUnmarshalBinary(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - u1 := UUID{} - err := u1.UnmarshalBinary(b1) - c.Assert(err, IsNil) - c.Assert(u1, Equals, u) - - b2 := []byte{} - u2 := UUID{} - err = u2.UnmarshalBinary(b2) - c.Assert(err, NotNil) -} - -func (s *codecTestSuite) TestFromString(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" - s2 := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" - s3 := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" - s4 := "6ba7b8109dad11d180b400c04fd430c8" - s5 := "{6ba7b8109dad11d180b400c04fd430c8}" - s6 := "urn:uuid:6ba7b8109dad11d180b400c04fd430c8" - - _, err := FromString("") - c.Assert(err, NotNil) - - u1, err := FromString(s1) - c.Assert(err, IsNil) - c.Assert(u1, Equals, u) - - u2, err := FromString(s2) - c.Assert(err, IsNil) - c.Assert(u2, Equals, u) - - u3, err := FromString(s3) - c.Assert(err, IsNil) - c.Assert(u3, Equals, u) - - u4, err := FromString(s4) - c.Assert(err, IsNil) - c.Assert(u4, Equals, u) - - u5, err := FromString(s5) - c.Assert(err, IsNil) - c.Assert(u5, Equals, u) - - u6, err := FromString(s6) - c.Assert(err, IsNil) - c.Assert(u6, Equals, u) +// Run runs the FromString test in a subtest of t, named by fst.variant. +func (fst fromStringTest) Run(t *testing.T) { + t.Run(fst.variant, func(t *testing.T) { + got, err := FromString(fst.input) + if err != nil { + t.Fatalf("FromString(%q): %v", fst.input, err) + } + if want := codecTestUUID; got != want { + t.Fatalf("FromString(%q) = %v, want %v", fst.input, got, want) + } + }) } -func (s *codecTestSuite) BenchmarkFromString(c *C) { - str := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" - for i := 0; i < c.N; i++ { - FromString(str) - } +// fromStringTests contains UUID variants that are expected to be parsed +// successfully by UnmarshalText / FromString. +// +// variants must be unique across elements of this slice. Please see the +// comment in fuzz.go if you change this slice or add new tests to it. +var fromStringTests = []fromStringTest{ + { + input: "6ba7b810-9dad-11d1-80b4-00c04fd430c8", + variant: "Canonical", + }, + { + input: "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", + variant: "BracedCanonical", + }, + { + input: "{6ba7b8109dad11d180b400c04fd430c8}", + variant: "BracedHashlike", + }, + { + input: "6ba7b8109dad11d180b400c04fd430c8", + variant: "Hashlike", + }, + { + input: "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8", + variant: "URNCanonical", + }, + { + input: "urn:uuid:6ba7b8109dad11d180b400c04fd430c8", + variant: "URNHashlike", + }, } -func (s *codecTestSuite) BenchmarkFromStringUrn(c *C) { - str := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" - for i := 0; i < c.N; i++ { - FromString(str) - } +var invalidFromStringInputs = []string{ + // short + "6ba7b810-9dad-11d1-80b4-00c04fd430c", + "6ba7b8109dad11d180b400c04fd430c", + + // invalid hex + "6ba7b8109dad11d180b400c04fd430q8", + + // long + "6ba7b810-9dad-11d1-80b4-00c04fd430c8=", + "6ba7b810-9dad-11d1-80b4-00c04fd430c8}", + "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}f", + "6ba7b810-9dad-11d1-80b4-00c04fd430c800c04fd430c8", + + // malformed in other ways + "ba7b8109dad11d180b400c04fd430c8}", + "6ba7b8109dad11d180b400c04fd430c86ba7b8109dad11d180b400c04fd430c8", + "urn:uuid:{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", + "uuid:urn:6ba7b810-9dad-11d1-80b4-00c04fd430c8", + "uuid:urn:6ba7b8109dad11d180b400c04fd430c8", + "6ba7b8109-dad-11d1-80b4-00c04fd430c8", + "6ba7b810-9dad1-1d1-80b4-00c04fd430c8", + "6ba7b810-9dad-11d18-0b4-00c04fd430c8", + "6ba7b810-9dad-11d1-80b40-0c04fd430c8", + "6ba7b810+9dad+11d1+80b4+00c04fd430c8", + "(6ba7b810-9dad-11d1-80b4-00c04fd430c8}", + "{6ba7b810-9dad-11d1-80b4-00c04fd430c8>", + "zba7b810-9dad-11d1-80b4-00c04fd430c8", + "6ba7b810-9dad11d180b400c04fd430c8", + "6ba7b8109dad-11d180b400c04fd430c8", + "6ba7b8109dad11d1-80b400c04fd430c8", + "6ba7b8109dad11d180b4-00c04fd430c8", } -func (s *codecTestSuite) BenchmarkFromStringWithBrackets(c *C) { - str := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" - for i := 0; i < c.N; i++ { - FromString(str) - } +func TestFromString(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + for _, fst := range fromStringTests { + fst.Run(t) + } + }) + t.Run("Invalid", func(t *testing.T) { + for _, s := range invalidFromStringInputs { + got, err := FromString(s) + if err == nil { + t.Errorf("FromString(%q): want err != nil, got %v", s, got) + } + } + }) } -func (s *codecTestSuite) TestFromStringShort(c *C) { - // Invalid 35-character UUID string - s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c" - - for i := len(s1); i >= 0; i-- { - _, err := FromString(s1[:i]) - c.Assert(err, NotNil) - } +func TestFromStringOrNil(t *testing.T) { + t.Run("Invalid", func(t *testing.T) { + s := "bad" + got := FromStringOrNil(s) + if got != Nil { + t.Errorf("FromStringOrNil(%q): got %v, want Nil", s, got) + } + }) + t.Run("Valid", func(t *testing.T) { + s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + got := FromStringOrNil(s) + if got != codecTestUUID { + t.Errorf("FromStringOrNil(%q): got %v, want %v", s, got, codecTestUUID) + } + }) } -func (s *codecTestSuite) TestFromStringLong(c *C) { - // Invalid 37+ character UUID string - strings := []string{ - "6ba7b810-9dad-11d1-80b4-00c04fd430c8=", - "6ba7b810-9dad-11d1-80b4-00c04fd430c8}", - "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}f", - "6ba7b810-9dad-11d1-80b4-00c04fd430c800c04fd430c8", +func TestMarshalBinary(t *testing.T) { + got, err := codecTestUUID.MarshalBinary() + if err != nil { + t.Fatal(err) } - - for _, str := range strings { - _, err := FromString(str) - c.Assert(err, NotNil) + if !bytes.Equal(got, codecTestData) { + t.Fatalf("%v.MarshalBinary() = %x, want %x", codecTestUUID, got, codecTestData) } } -func (s *codecTestSuite) TestFromStringInvalid(c *C) { - // Invalid UUID string formats - strings := []string{ - "6ba7b8109dad11d180b400c04fd430c86ba7b8109dad11d180b400c04fd430c8", - "urn:uuid:{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", - "uuid:urn:6ba7b810-9dad-11d1-80b4-00c04fd430c8", - "uuid:urn:6ba7b8109dad11d180b400c04fd430c8", - "6ba7b8109-dad-11d1-80b4-00c04fd430c8", - "6ba7b810-9dad1-1d1-80b4-00c04fd430c8", - "6ba7b810-9dad-11d18-0b4-00c04fd430c8", - "6ba7b810-9dad-11d1-80b40-0c04fd430c8", - "6ba7b810+9dad+11d1+80b4+00c04fd430c8", - "(6ba7b810-9dad-11d1-80b4-00c04fd430c8}", - "{6ba7b810-9dad-11d1-80b4-00c04fd430c8>", - "zba7b810-9dad-11d1-80b4-00c04fd430c8", - "6ba7b810-9dad11d180b400c04fd430c8", - "6ba7b8109dad-11d180b400c04fd430c8", - "6ba7b8109dad11d1-80b400c04fd430c8", - "6ba7b8109dad11d180b4-00c04fd430c8", +func TestMarshalText(t *testing.T) { + want := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + got, err := codecTestUUID.MarshalText() + if err != nil { + t.Fatal(err) } - - for _, str := range strings { - _, err := FromString(str) - c.Assert(err, NotNil) + if !bytes.Equal(got, want) { + t.Errorf("%v.MarshalText(): got %s, want %s", codecTestUUID, got, want) } } -func (s *codecTestSuite) TestFromStringOrNil(c *C) { - expect := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - u := FromStringOrNil("") - c.Assert(u, Equals, Nil) +var stringBenchmarkSink string - s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" - u = FromStringOrNil(s1) - c.Assert(u, Equals, expect) +func BenchmarkString(b *testing.B) { + for i := 0; i < b.N; i++ { + stringBenchmarkSink = codecTestUUID.String() + } } -func (s *codecTestSuite) TestFromBytesOrNil(c *C) { - expect := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - b := []byte{} - u := FromBytesOrNil(b) - c.Assert(u, Equals, Nil) - - b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - u = FromBytesOrNil(b1) - c.Assert(u, Equals, expect) +func BenchmarkFromBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + FromBytes(codecTestData) + } } -func (s *codecTestSuite) TestMarshalText(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - - b2, err := u.MarshalText() - c.Assert(err, IsNil) - c.Assert(bytes.Equal(b1, b2), Equals, true) +func BenchmarkFromString(b *testing.B) { + b.Run("canonical", func(b *testing.B) { + for i := 0; i < b.N; i++ { + FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + } + }) + b.Run("urn", func(b *testing.B) { + for i := 0; i < b.N; i++ { + FromString("urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8") + } + }) + b.Run("braced", func(b *testing.B) { + for i := 0; i < b.N; i++ { + FromString("{6ba7b810-9dad-11d1-80b4-00c04fd430c8}") + } + }) } -func (s *codecTestSuite) BenchmarkMarshalText(c *C) { - u, err := NewV4() - c.Assert(err, IsNil) - for i := 0; i < c.N; i++ { - u.MarshalText() +func BenchmarkMarshalBinary(b *testing.B) { + for i := 0; i < b.N; i++ { + codecTestUUID.MarshalBinary() } } -func (s *codecTestSuite) TestUnmarshalText(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - - u1 := UUID{} - err := u1.UnmarshalText(b1) - c.Assert(err, IsNil) - c.Assert(u1, Equals, u) - - b2 := []byte("") - u2 := UUID{} - err = u2.UnmarshalText(b2) - c.Assert(err, NotNil) -} - -func (s *codecTestSuite) BenchmarkUnmarshalText(c *C) { - bytes := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - u := UUID{} - for i := 0; i < c.N; i++ { - u.UnmarshalText(bytes) +func BenchmarkMarshalText(b *testing.B) { + for i := 0; i < b.N; i++ { + codecTestUUID.MarshalText() } } -var sink string +var seedFuzzCorpus = flag.Bool("seed_fuzz_corpus", false, "seed fuzz test corpus") -func (s *codecTestSuite) BenchmarkMarshalToString(c *C) { - u, err := NewV4() - c.Assert(err, IsNil) - for i := 0; i < c.N; i++ { - sink = u.String() +func TestSeedFuzzCorpus(t *testing.T) { + // flag.Parse() is called for us by the test binary. + if !*seedFuzzCorpus { + t.Skip("seeding fuzz test corpus only on demand") + } + corpusDir := filepath.Join(".", "testdata", "corpus") + writeSeedFile := func(name, data string) error { + path := filepath.Join(corpusDir, name) + return ioutil.WriteFile(path, []byte(data), os.ModePerm) + } + for _, fst := range fromStringTests { + name := "seed_valid_" + fst.variant + if err := writeSeedFile(name, fst.input); err != nil { + t.Fatal(err) + } + } + for i, s := range invalidFromStringInputs { + name := fmt.Sprintf("seed_invalid_%d", i) + if err := writeSeedFile(name, s); err != nil { + t.Fatal(err) + } } } diff --git a/fuzz.go b/fuzz.go index 7f07336..afaefbc 100644 --- a/fuzz.go +++ b/fuzz.go @@ -30,10 +30,14 @@ package uuid // $ go get github.com/dvyukov/go-fuzz/... // $ cd $GOPATH/src/github.com/gofrs/uuid // $ go-fuzz-build github.com/gofrs/uuid -// $ go-fuzz -bin=uuid-fuzz.zip -workdir=/path/to/work/directory +// $ go-fuzz -bin=uuid-fuzz.zip -workdir=./testdata // -// TODO(acln): clarify how to set up work directory, seed initial corpus -// with UUIDs used by FromString tests +// If you make significant changes to FromString / UnmarshalText and add +// new cases to fromStringTests (in codec_test.go), please run +// +// $ go test -seed_fuzz_corpus +// +// to seed the corpus with the new interesting inputs, then run the fuzzer. func Fuzz(data []byte) int { _, err := FromString(string(data)) if err != nil { diff --git a/generator_test.go b/generator_test.go index 0ac5be5..c5c62df 100644 --- a/generator_test.go +++ b/generator_test.go @@ -26,40 +26,55 @@ import ( "crypto/rand" "fmt" "net" + "testing" "time" - - . "gopkg.in/check.v1" ) -type faultyReader struct { - callsNum int - readToFail int // Read call number to fail +func TestGenerator(t *testing.T) { + t.Run("NewV1", testNewV1) + t.Run("NewV2", testNewV2) + t.Run("NewV3", testNewV3) + t.Run("NewV4", testNewV4) + t.Run("NewV5", testNewV5) } -func (r *faultyReader) Read(dest []byte) (int, error) { - r.callsNum++ - if (r.callsNum - 1) == r.readToFail { - return 0, fmt.Errorf("io: reader is faulty") - } - return rand.Read(dest) +func testNewV1(t *testing.T) { + t.Run("Basic", testNewV1Basic) + t.Run("DifferentAcrossCalls", testNewV1DifferentAcrossCalls) + t.Run("StaleEpoch", testNewV1StaleEpoch) + t.Run("FaultyRand", testNewV1FaultyRand) + t.Run("MissingNetwork", testNewV1MissingNetwork) + t.Run("MissingNetworkFaultyRand", testNewV1MissingNetworkFaultyRand) } -type genTestSuite struct{} - -var _ = Suite(&genTestSuite{}) +func testNewV1Basic(t *testing.T) { + u, err := NewV1() + if err != nil { + t.Fatal(err) + } + if got, want := u.Version(), V1; got != want { + t.Errorf("generated UUID with version %d, want %d", got, want) + } + if got, want := u.Variant(), VariantRFC4122; got != want { + t.Errorf("generated UUID with variant %d, want %d", got, want) + } +} -func (s *genTestSuite) TestNewV1(c *C) { +func testNewV1DifferentAcrossCalls(t *testing.T) { u1, err := NewV1() - c.Assert(err, IsNil) - c.Assert(u1.Version(), Equals, V1) - c.Assert(u1.Variant(), Equals, VariantRFC4122) - + if err != nil { + t.Fatal(err) + } u2, err := NewV1() - c.Assert(err, IsNil) - c.Assert(u1, Not(Equals), u2) + if err != nil { + t.Fatal(err) + } + if u1 == u2 { + t.Errorf("generated identical UUIDs across calls: %v", u1) + } } -func (s *genTestSuite) TestNewV1EpochStale(c *C) { +func testNewV1StaleEpoch(t *testing.T) { g := &rfc4122Generator{ epochFunc: func() time.Time { return time.Unix(0, 0) @@ -68,24 +83,36 @@ func (s *genTestSuite) TestNewV1EpochStale(c *C) { rand: rand.Reader, } u1, err := g.NewV1() - c.Assert(err, IsNil) + if err != nil { + t.Fatal(err) + } u2, err := g.NewV1() - c.Assert(err, IsNil) - c.Assert(u1, Not(Equals), u2) + if err != nil { + t.Fatal(err) + } + if u1 == u2 { + t.Errorf("generated identical UUIDs across calls: %v", u1) + } } -func (s *genTestSuite) TestNewV1FaultyRand(c *C) { +func testNewV1FaultyRand(t *testing.T) { g := &rfc4122Generator{ epochFunc: time.Now, hwAddrFunc: defaultHWAddrFunc, - rand: &faultyReader{}, + rand: &faultyReader{ + readToFail: 0, // fail immediately + }, + } + u, err := g.NewV1() + if err == nil { + t.Fatalf("got %v, want error", u) + } + if u != Nil { + t.Fatalf("got %v on error, want Nil", u) } - u1, err := g.NewV1() - c.Assert(err, NotNil) - c.Assert(u1, Equals, Nil) } -func (s *genTestSuite) TestNewV1MissingNetworkInterfaces(c *C) { +func testNewV1MissingNetwork(t *testing.T) { g := &rfc4122Generator{ epochFunc: time.Now, hwAddrFunc: func() (net.HardwareAddr, error) { @@ -94,10 +121,12 @@ func (s *genTestSuite) TestNewV1MissingNetworkInterfaces(c *C) { rand: rand.Reader, } _, err := g.NewV1() - c.Assert(err, IsNil) + if err != nil { + t.Errorf("did not handle missing network interfaces: %v", err) + } } -func (s *genTestSuite) TestNewV1MissingNetInterfacesAndFaultyRand(c *C) { +func testNewV1MissingNetworkFaultyRand(t *testing.T) { g := &rfc4122Generator{ epochFunc: time.Now, hwAddrFunc: func() (net.HardwareAddr, error) { @@ -107,133 +136,254 @@ func (s *genTestSuite) TestNewV1MissingNetInterfacesAndFaultyRand(c *C) { readToFail: 1, }, } - u1, err := g.NewV1() - c.Assert(err, NotNil) - c.Assert(u1, Equals, Nil) -} - -func (s *genTestSuite) BenchmarkNewV1(c *C) { - for i := 0; i < c.N; i++ { - NewV1() + u, err := g.NewV1() + if err == nil { + t.Errorf("did not error on faulty reader and missing network, got %v", u) } } -func (s *genTestSuite) TestNewV2(c *C) { - u1, err := NewV2(DomainPerson) - c.Assert(err, IsNil) - c.Assert(u1.Version(), Equals, V2) - c.Assert(u1.Variant(), Equals, VariantRFC4122) +func testNewV2(t *testing.T) { + t.Run("Basic", testNewV2Basic) + t.Run("DifferentAcrossCalls", testNewV2DifferentAcrossCalls) + t.Run("FaultyRand", testNewV2FaultyRand) +} - u2, err := NewV2(DomainGroup) - c.Assert(err, IsNil) - c.Assert(u2.Version(), Equals, V2) - c.Assert(u2.Variant(), Equals, VariantRFC4122) +func testNewV2Basic(t *testing.T) { + domains := []byte{ + DomainPerson, + DomainGroup, + DomainOrg, + } + for _, domain := range domains { + u, err := NewV2(domain) + if err != nil { + t.Errorf("NewV2(%d): %v", domain, err) + } + if got, want := u.Version(), V2; got != want { + t.Errorf("NewV2(%d) generated UUID with version %d, want %d", domain, got, want) + } + if got, want := u.Variant(), VariantRFC4122; got != want { + t.Errorf("NewV2(%d) generated UUID with variant %d, want %d", domain, got, want) + } + } +} - u3, err := NewV2(DomainOrg) - c.Assert(err, IsNil) - c.Assert(u3.Version(), Equals, V2) - c.Assert(u3.Variant(), Equals, VariantRFC4122) +func testNewV2DifferentAcrossCalls(t *testing.T) { + u1, err := NewV2(DomainOrg) + if err != nil { + t.Fatal(err) + } + u2, err := NewV2(DomainOrg) + if err != nil { + t.Fatal(err) + } + if u1 == u2 { + t.Errorf("generated identical UUIDs across calls: %v", u1) + } } -func (s *genTestSuite) TestNewV2FaultyRand(c *C) { +func testNewV2FaultyRand(t *testing.T) { g := &rfc4122Generator{ epochFunc: time.Now, hwAddrFunc: defaultHWAddrFunc, - rand: &faultyReader{}, + rand: &faultyReader{ + readToFail: 0, // fail immediately + }, + } + u, err := g.NewV2(DomainPerson) + if err == nil { + t.Fatalf("got %v, want error", u) + } + if u != Nil { + t.Fatalf("got %v on error, want Nil", u) } - u1, err := g.NewV2(DomainPerson) - c.Assert(err, NotNil) - c.Assert(u1, Equals, Nil) } -func (s *genTestSuite) BenchmarkNewV2(c *C) { - for i := 0; i < c.N; i++ { - NewV2(DomainPerson) - } +func testNewV3(t *testing.T) { + t.Run("Basic", testNewV3Basic) + t.Run("EqualNames", testNewV3EqualNames) + t.Run("DifferentNamespaces", testNewV3DifferentNamespaces) } -func (s *genTestSuite) TestNewV3(c *C) { - u1 := NewV3(NamespaceDNS, "www.example.com") - c.Assert(u1.Version(), Equals, V3) - c.Assert(u1.Variant(), Equals, VariantRFC4122) - c.Assert(u1.String(), Equals, "5df41881-3aed-3515-88a7-2f4a814cf09e") +func testNewV3Basic(t *testing.T) { + ns := NamespaceDNS + name := "www.example.com" + u := NewV3(ns, name) + if got, want := u.Version(), V3; got != want { + t.Errorf("NewV3(%v, %q): got version %d, want %d", ns, name, got, want) + } + if got, want := u.Variant(), VariantRFC4122; got != want { + t.Errorf("NewV3(%v, %q): got variant %d, want %d", ns, name, got, want) + } + want := "5df41881-3aed-3515-88a7-2f4a814cf09e" + if got := u.String(); got != want { + t.Errorf("NewV3(%v, %q) = %q, want %q", ns, name, got, want) + } +} - u2 := NewV3(NamespaceDNS, "example.com") - c.Assert(u2, Not(Equals), u1) +func testNewV3EqualNames(t *testing.T) { + ns := NamespaceDNS + name := "example.com" + u1 := NewV3(ns, name) + u2 := NewV3(ns, name) + if u1 != u2 { + t.Errorf("NewV3(%v, %q) generated %v and %v across two calls", ns, name, u1, u2) + } +} - u3 := NewV3(NamespaceDNS, "example.com") - c.Assert(u3, Equals, u2) +func testNewV3DifferentNamespaces(t *testing.T) { + name := "example.com" + ns1 := NamespaceDNS + ns2 := NamespaceURL + u1 := NewV3(ns1, name) + u2 := NewV3(ns2, name) + if u1 == u2 { + t.Errorf("NewV3(%v, %q) == NewV3(%d, %q) (%v)", ns1, name, ns2, name, u1) + } +} - u4 := NewV3(NamespaceURL, "example.com") - c.Assert(u4, Not(Equals), u3) +func testNewV4(t *testing.T) { + t.Run("Basic", testNewV4Basic) + t.Run("DifferentAcrossCalls", testNewV4DifferentAcrossCalls) + t.Run("FaultyRand", testNewV4FaultyRand) + t.Run("ShortRandomRead", testNewV4ShortRandomRead) } -func (s *genTestSuite) BenchmarkNewV3(c *C) { - for i := 0; i < c.N; i++ { - NewV3(NamespaceDNS, "www.example.com") +func testNewV4Basic(t *testing.T) { + u, err := NewV4() + if err != nil { + t.Fatal(err) + } + if got, want := u.Version(), V4; got != want { + t.Errorf("got version %d, want %d", got, want) + } + if got, want := u.Variant(), VariantRFC4122; got != want { + t.Errorf("got variant %d, want %d", got, want) } } -func (s *genTestSuite) TestNewV4(c *C) { +func testNewV4DifferentAcrossCalls(t *testing.T) { u1, err := NewV4() - c.Assert(err, IsNil) - c.Assert(u1.Version(), Equals, V4) - c.Assert(u1.Variant(), Equals, VariantRFC4122) - + if err != nil { + t.Fatal(err) + } u2, err := NewV4() - c.Assert(err, IsNil) - c.Assert(u1, Not(Equals), u2) + if err != nil { + t.Fatal(err) + } + if u1 == u2 { + t.Errorf("generated identical UUIDs across calls: %v", u1) + } } -func (s *genTestSuite) TestNewV4FaultyRand(c *C) { +func testNewV4FaultyRand(t *testing.T) { g := &rfc4122Generator{ epochFunc: time.Now, hwAddrFunc: defaultHWAddrFunc, - rand: &faultyReader{}, + rand: &faultyReader{ + readToFail: 0, // fail immediately + }, + } + u, err := g.NewV4() + if err == nil { + t.Errorf("got %v, nil error", u) } - u1, err := g.NewV4() - c.Assert(err, NotNil) - c.Assert(u1, Equals, Nil) } -func (s *genTestSuite) TestNewV4IncompleteRandomReader(c *C) { - r := bytes.NewReader([]byte{42}) - +func testNewV4ShortRandomRead(t *testing.T) { g := &rfc4122Generator{ epochFunc: time.Now, hwAddrFunc: func() (net.HardwareAddr, error) { return []byte{}, fmt.Errorf("uuid: no hw address found") }, - rand: r, + rand: bytes.NewReader([]byte{42}), + } + u, err := g.NewV4() + if err == nil { + t.Errorf("got %v, nil error", u) } - _, err := g.NewV4() - c.Assert(err, NotNil) } -func (s *genTestSuite) BenchmarkNewV4(c *C) { - for i := 0; i < c.N; i++ { - NewV4() +func testNewV5(t *testing.T) { + t.Run("Basic", testNewV5Basic) + t.Run("EqualNames", testNewV5EqualNames) + t.Run("DifferentNamespaces", testNewV5DifferentNamespaces) +} + +func testNewV5Basic(t *testing.T) { + ns := NamespaceDNS + name := "www.example.com" + u := NewV5(ns, name) + if got, want := u.Version(), V5; got != want { + t.Errorf("NewV5(%v, %q): got version %d, want %d", ns, name, got, want) + } + if got, want := u.Variant(), VariantRFC4122; got != want { + t.Errorf("NewV5(%v, %q): got variant %d, want %d", ns, name, got, want) + } + want := "2ed6657d-e927-568b-95e1-2665a8aea6a2" + if got := u.String(); got != want { + t.Errorf("NewV5(%v, %q) = %q, want %q", ns, name, got, want) } } -func (s *genTestSuite) TestNewV5(c *C) { - u1 := NewV5(NamespaceDNS, "www.example.com") - c.Assert(u1.Version(), Equals, V5) - c.Assert(u1.Variant(), Equals, VariantRFC4122) - c.Assert(u1.String(), Equals, "2ed6657d-e927-568b-95e1-2665a8aea6a2") +func testNewV5EqualNames(t *testing.T) { + ns := NamespaceDNS + name := "example.com" + u1 := NewV5(ns, name) + u2 := NewV5(ns, name) + if u1 != u2 { + t.Errorf("NewV5(%v, %q) generated %v and %v across two calls", ns, name, u1, u2) + } +} - u2 := NewV5(NamespaceDNS, "example.com") - c.Assert(u2, Not(Equals), u1) +func testNewV5DifferentNamespaces(t *testing.T) { + name := "example.com" + ns1 := NamespaceDNS + ns2 := NamespaceURL + u1 := NewV5(ns1, name) + u2 := NewV5(ns2, name) + if u1 == u2 { + t.Errorf("NewV5(%v, %q) == NewV5(%v, %q) (%v)", ns1, name, ns2, name, u1) + } +} - u3 := NewV5(NamespaceDNS, "example.com") - c.Assert(u3, Equals, u2) +func BenchmarkGenerator(b *testing.B) { + b.Run("NewV1", func(b *testing.B) { + for i := 0; i < b.N; i++ { + NewV1() + } + }) + b.Run("NewV2", func(b *testing.B) { + for i := 0; i < b.N; i++ { + NewV2(DomainOrg) + } + }) + b.Run("NewV3", func(b *testing.B) { + for i := 0; i < b.N; i++ { + NewV3(NamespaceDNS, "www.example.com") + } + }) + b.Run("NewV4", func(b *testing.B) { + for i := 0; i < b.N; i++ { + NewV4() + } + }) + b.Run("NewV5", func(b *testing.B) { + for i := 0; i < b.N; i++ { + NewV5(NamespaceDNS, "www.example.com") + } + }) +} - u4 := NewV5(NamespaceURL, "example.com") - c.Assert(u4, Not(Equals), u3) +type faultyReader struct { + callsNum int + readToFail int // Read call number to fail } -func (s *genTestSuite) BenchmarkNewV5(c *C) { - for i := 0; i < c.N; i++ { - NewV5(NamespaceDNS, "www.example.com") +func (r *faultyReader) Read(dest []byte) (int, error) { + r.callsNum++ + if (r.callsNum - 1) == r.readToFail { + return 0, fmt.Errorf("io: reader is faulty") } + return rand.Read(dest) } diff --git a/sql_test.go b/sql_test.go index 74255f5..cf2757c 100644 --- a/sql_test.go +++ b/sql_test.go @@ -21,116 +21,144 @@ package uuid -import ( - . "gopkg.in/check.v1" -) - -type sqlTestSuite struct{} - -var _ = Suite(&sqlTestSuite{}) - -func (s *sqlTestSuite) TestValue(c *C) { - u, err := FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - c.Assert(err, IsNil) - - val, err := u.Value() - c.Assert(err, IsNil) - c.Assert(val, Equals, u.String()) +import "testing" + +func TestSQL(t *testing.T) { + t.Run("Value", testSQLValue) + t.Run("Scan", func(t *testing.T) { + t.Run("Binary", testSQLScanBinary) + t.Run("String", testSQLScanString) + t.Run("Text", testSQLScanText) + t.Run("Unsupported", testSQLScanUnsupported) + t.Run("Nil", testSQLScanNil) + }) } -func (s *sqlTestSuite) TestValueNil(c *C) { - u := UUID{} - - val, err := u.Value() - c.Assert(err, IsNil) - c.Assert(val, Equals, Nil.String()) -} - -func (s *sqlTestSuite) TestNullUUIDValueNil(c *C) { - u := NullUUID{} - - val, err := u.Value() - c.Assert(err, IsNil) - c.Assert(val, IsNil) -} - -func (s *sqlTestSuite) TestScanBinary(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - u1 := UUID{} - err := u1.Scan(b1) - c.Assert(err, IsNil) - c.Assert(u, Equals, u1) - - b2 := []byte{} - u2 := UUID{} - - err = u2.Scan(b2) - c.Assert(err, NotNil) +func testSQLValue(t *testing.T) { + v, err := codecTestUUID.Value() + if err != nil { + t.Fatal(err) + } + got, ok := v.(string) + if !ok { + t.Fatalf("Value() returned %T, want string", v) + } + if want := codecTestUUID.String(); got != want { + t.Errorf("Value() == %q, want %q", got, want) + } } -func (s *sqlTestSuite) TestScanString(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" - - u1 := UUID{} - err := u1.Scan(s1) - c.Assert(err, IsNil) - c.Assert(u, Equals, u1) - - s2 := "" - u2 := UUID{} - - err = u2.Scan(s2) - c.Assert(err, NotNil) +func testSQLScanBinary(t *testing.T) { + got := UUID{} + err := got.Scan(codecTestData) + if err != nil { + t.Fatal(err) + } + if got != codecTestUUID { + t.Errorf("Scan(%x): got %v, want %v", codecTestData, got, codecTestUUID) + } } -func (s *sqlTestSuite) TestScanText(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - - u1 := UUID{} - err := u1.Scan(b1) - c.Assert(err, IsNil) - c.Assert(u, Equals, u1) - - b2 := []byte("") - u2 := UUID{} - err = u2.Scan(b2) - c.Assert(err, NotNil) +func testSQLScanString(t *testing.T) { + s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + got := UUID{} + err := got.Scan(s) + if err != nil { + t.Fatal(err) + } + if got != codecTestUUID { + t.Errorf("Scan(%q): got %v, want %v", s, got, codecTestUUID) + } } -func (s *sqlTestSuite) TestScanUnsupported(c *C) { - u := UUID{} - - err := u.Scan(true) - c.Assert(err, NotNil) +func testSQLScanText(t *testing.T) { + text := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + got := UUID{} + err := got.Scan(text) + if err != nil { + t.Fatal(err) + } + if got != codecTestUUID { + t.Errorf("Scan(%q): got %v, want %v", text, got, codecTestUUID) + } } -func (s *sqlTestSuite) TestScanNil(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - err := u.Scan(nil) - c.Assert(err, NotNil) +func testSQLScanUnsupported(t *testing.T) { + unsupported := []interface{}{ + true, + 42, + } + for _, v := range unsupported { + got := UUID{} + err := got.Scan(v) + if err == nil { + t.Errorf("Scan(%T) succeeded, got %v", v, got) + } + } } -func (s *sqlTestSuite) TestNullUUIDScanValid(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" - - u1 := NullUUID{} - err := u1.Scan(s1) - c.Assert(err, IsNil) - c.Assert(u1.Valid, Equals, true) - c.Assert(u1.UUID, Equals, u) +func testSQLScanNil(t *testing.T) { + got := UUID{} + err := got.Scan(nil) + if err == nil { + t.Errorf("Scan(nil) succeeded, got %v", got) + } } -func (s *sqlTestSuite) TestNullUUIDScanNil(c *C) { - u := NullUUID{UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}, true} - - err := u.Scan(nil) - c.Assert(err, IsNil) - c.Assert(u.Valid, Equals, false) - c.Assert(u.UUID, Equals, Nil) +func TestNullUUID(t *testing.T) { + t.Run("NilValue", func(t *testing.T) { + nu := NullUUID{} + got, err := nu.Value() + if got != nil { + t.Errorf("null NullUUID.Value returned non-nil driver.Value") + } + if err != nil { + t.Errorf("null NullUUID.Value returned non-nil error") + } + }) + t.Run("ValidValue", func(t *testing.T) { + nu := NullUUID{ + Valid: true, + UUID: codecTestUUID, + } + got, err := nu.Value() + if err != nil { + t.Fatal(err) + } + s, ok := got.(string) + if !ok { + t.Errorf("Value() returned %T, want string", got) + } + want := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + if s != want { + t.Errorf("%v.Value() == %s, want %s", nu, s, want) + } + }) + t.Run("ScanValid", func(t *testing.T) { + s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + u := NullUUID{} + err := u.Scan(s) + if err != nil { + t.Fatal(err) + } + if !u.Valid { + t.Errorf("Valid == false after Scan(%q)", s) + } + if u.UUID != codecTestUUID { + t.Errorf("UUID == %v after Scan(%q), want %v", u.UUID, s, codecTestUUID) + } + }) + t.Run("ScanNil", func(t *testing.T) { + u := NullUUID{} + err := u.Scan(nil) + if err != nil { + t.Fatal(err) + } + if u.Valid { + t.Error("NullUUID is valid after Scan(nil)") + } + if u.UUID != Nil { + t.Errorf("NullUUID.UUID is %v after Scan(nil) want Nil", u.UUID) + } + }) } diff --git a/testdata/corpus/1416586f4a34d02bcb506f6107b40df512b9f2f9 b/testdata/corpus/1416586f4a34d02bcb506f6107b40df512b9f2f9 new file mode 100644 index 0000000..cfb2480 --- /dev/null +++ b/testdata/corpus/1416586f4a34d02bcb506f6107b40df512b9f2f9 @@ -0,0 +1 @@ +zba7b810-9dad-11d1-80b4-00c04fd4 \ No newline at end of file diff --git a/testdata/corpus/3b46a7e7b02ec193581e6c9fa2c8a72f50a64e08-1 b/testdata/corpus/3b46a7e7b02ec193581e6c9fa2c8a72f50a64e08-1 new file mode 100644 index 0000000..77b9420 --- /dev/null +++ b/testdata/corpus/3b46a7e7b02ec193581e6c9fa2c8a72f50a64e08-1 @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80F4-00c"4fd430c8 \ No newline at end of file diff --git a/testdata/corpus/50c54bb75fcfdc488f162bf2f0c6dec6103bfa18-5 b/testdata/corpus/50c54bb75fcfdc488f162bf2f0c6dec6103bfa18-5 new file mode 100644 index 0000000..17e57ce --- /dev/null +++ b/testdata/corpus/50c54bb75fcfdc488f162bf2f0c6dec6103bfa18-5 @@ -0,0 +1 @@ +6ad1DdE8dda91DdE80F400c0Bool30t: \ No newline at end of file diff --git a/testdata/corpus/69c581ab749cbd56be8684d3a58ac2cfab9af0f4-5 b/testdata/corpus/69c581ab749cbd56be8684d3a58ac2cfab9af0f4-5 new file mode 100644 index 0000000..f53c1bd --- /dev/null +++ b/testdata/corpus/69c581ab749cbd56be8684d3a58ac2cfab9af0f4-5 @@ -0,0 +1 @@ +6ba7b810Edad1DdE80F400c0Bool30c8 \ No newline at end of file diff --git a/testdata/corpus/752bf000e0bff06777dd0d6f0be6353844de678a-3 b/testdata/corpus/752bf000e0bff06777dd0d6f0be6353844de678a-3 new file mode 100644 index 0000000..6bcb9a1 --- /dev/null +++ b/testdata/corpus/752bf000e0bff06777dd0d6f0be6353844de678a-3 @@ -0,0 +1 @@ +6ba7b8109dad1Dd180F400c0Bool30c8 \ No newline at end of file diff --git a/testdata/corpus/a4483762d4ece8466d82cca5cacd35a0829c4e60-2 b/testdata/corpus/a4483762d4ece8466d82cca5cacd35a0829c4e60-2 new file mode 100644 index 0000000..88427b7 --- /dev/null +++ b/testdata/corpus/a4483762d4ece8466d82cca5cacd35a0829c4e60-2 @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80F4-F0c"4fd430c8 \ No newline at end of file diff --git a/testdata/corpus/d0952c45e0c823fc5cc12bcf7d9b877d150ab523-1 b/testdata/corpus/d0952c45e0c823fc5cc12bcf7d9b877d150ab523-1 new file mode 100644 index 0000000..b3b8228 --- /dev/null +++ b/testdata/corpus/d0952c45e0c823fc5cc12bcf7d9b877d150ab523-1 @@ -0,0 +1 @@ +6ba7b8109dad11d180b400c0Bool30c8 \ No newline at end of file diff --git a/testdata/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709 b/testdata/corpus/da39a3ee5e6b4b0d3255bfef95601890afd80709 new file mode 100644 index 0000000..e69de29 diff --git a/testdata/corpus/e2b84d2065846891f18ae109b12e01d224e1c7c3-4 b/testdata/corpus/e2b84d2065846891f18ae109b12e01d224e1c7c3-4 new file mode 100644 index 0000000..abff4da --- /dev/null +++ b/testdata/corpus/e2b84d2065846891f18ae109b12e01d224e1c7c3-4 @@ -0,0 +1 @@ +6ba7b8109dad1DdE80F400c0Bool30c8 \ No newline at end of file diff --git a/testdata/corpus/e320d749435115e874f77420e17d0937e07f69f3-2 b/testdata/corpus/e320d749435115e874f77420e17d0937e07f69f3-2 new file mode 100644 index 0000000..b71e8b2 --- /dev/null +++ b/testdata/corpus/e320d749435115e874f77420e17d0937e07f69f3-2 @@ -0,0 +1 @@ +6ba7b8109dad1Dd180b400c0Bool30c8 \ No newline at end of file diff --git a/testdata/corpus/ed132d47d757f6468443a22df8a2a965efb34098-7 b/testdata/corpus/ed132d47d757f6468443a22df8a2a965efb34098-7 new file mode 100644 index 0000000..a40ccde --- /dev/null +++ b/testdata/corpus/ed132d47d757f6468443a22df8a2a965efb34098-7 @@ -0,0 +1 @@ +6ba1DdE8dDAE8DdE80F400c0BoUl30to \ No newline at end of file diff --git a/testdata/corpus/eeefb01f7bb3c627aedb292c994b20f739ffd613-6 b/testdata/corpus/eeefb01f7bb3c627aedb292c994b20f739ffd613-6 new file mode 100644 index 0000000..4117221 --- /dev/null +++ b/testdata/corpus/eeefb01f7bb3c627aedb292c994b20f739ffd613-6 @@ -0,0 +1 @@ +6ad1DdE8dDdE8DdE80F400c0Bool30t: \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_0 b/testdata/corpus/seed_invalid_0 new file mode 100755 index 0000000..02965f8 --- /dev/null +++ b/testdata/corpus/seed_invalid_0 @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80b4-00c04fd430c \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_1 b/testdata/corpus/seed_invalid_1 new file mode 100755 index 0000000..3c7f5f6 --- /dev/null +++ b/testdata/corpus/seed_invalid_1 @@ -0,0 +1 @@ +6ba7b8109dad11d180b400c04fd430c \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_10 b/testdata/corpus/seed_invalid_10 new file mode 100755 index 0000000..ec890f3 --- /dev/null +++ b/testdata/corpus/seed_invalid_10 @@ -0,0 +1 @@ +uuid:urn:6ba7b810-9dad-11d1-80b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_11 b/testdata/corpus/seed_invalid_11 new file mode 100755 index 0000000..266a823 --- /dev/null +++ b/testdata/corpus/seed_invalid_11 @@ -0,0 +1 @@ +uuid:urn:6ba7b8109dad11d180b400c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_12 b/testdata/corpus/seed_invalid_12 new file mode 100755 index 0000000..06f8ad2 --- /dev/null +++ b/testdata/corpus/seed_invalid_12 @@ -0,0 +1 @@ +6ba7b8109-dad-11d1-80b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_13 b/testdata/corpus/seed_invalid_13 new file mode 100755 index 0000000..302b9c3 --- /dev/null +++ b/testdata/corpus/seed_invalid_13 @@ -0,0 +1 @@ +6ba7b810-9dad1-1d1-80b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_14 b/testdata/corpus/seed_invalid_14 new file mode 100755 index 0000000..c37896c --- /dev/null +++ b/testdata/corpus/seed_invalid_14 @@ -0,0 +1 @@ +6ba7b810-9dad-11d18-0b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_15 b/testdata/corpus/seed_invalid_15 new file mode 100755 index 0000000..bb279bd --- /dev/null +++ b/testdata/corpus/seed_invalid_15 @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80b40-0c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_16 b/testdata/corpus/seed_invalid_16 new file mode 100755 index 0000000..2c8be7d --- /dev/null +++ b/testdata/corpus/seed_invalid_16 @@ -0,0 +1 @@ +6ba7b810+9dad+11d1+80b4+00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_17 b/testdata/corpus/seed_invalid_17 new file mode 100755 index 0000000..129f752 --- /dev/null +++ b/testdata/corpus/seed_invalid_17 @@ -0,0 +1 @@ +(6ba7b810-9dad-11d1-80b4-00c04fd430c8} \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_18 b/testdata/corpus/seed_invalid_18 new file mode 100755 index 0000000..ed41a50 --- /dev/null +++ b/testdata/corpus/seed_invalid_18 @@ -0,0 +1 @@ +{6ba7b810-9dad-11d1-80b4-00c04fd430c8> \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_19 b/testdata/corpus/seed_invalid_19 new file mode 100755 index 0000000..a296f9e --- /dev/null +++ b/testdata/corpus/seed_invalid_19 @@ -0,0 +1 @@ +zba7b810-9dad-11d1-80b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_2 b/testdata/corpus/seed_invalid_2 new file mode 100755 index 0000000..e294615 --- /dev/null +++ b/testdata/corpus/seed_invalid_2 @@ -0,0 +1 @@ +6ba7b8109dad11d180b400c04fd430q8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_20 b/testdata/corpus/seed_invalid_20 new file mode 100755 index 0000000..6e5d2d5 --- /dev/null +++ b/testdata/corpus/seed_invalid_20 @@ -0,0 +1 @@ +6ba7b810-9dad11d180b400c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_21 b/testdata/corpus/seed_invalid_21 new file mode 100755 index 0000000..53ebad9 --- /dev/null +++ b/testdata/corpus/seed_invalid_21 @@ -0,0 +1 @@ +6ba7b8109dad-11d180b400c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_22 b/testdata/corpus/seed_invalid_22 new file mode 100755 index 0000000..c08019c --- /dev/null +++ b/testdata/corpus/seed_invalid_22 @@ -0,0 +1 @@ +6ba7b8109dad11d1-80b400c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_23 b/testdata/corpus/seed_invalid_23 new file mode 100755 index 0000000..8c32062 --- /dev/null +++ b/testdata/corpus/seed_invalid_23 @@ -0,0 +1 @@ +6ba7b8109dad11d180b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_3 b/testdata/corpus/seed_invalid_3 new file mode 100755 index 0000000..2afa5c9 --- /dev/null +++ b/testdata/corpus/seed_invalid_3 @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80b4-00c04fd430c8= \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_4 b/testdata/corpus/seed_invalid_4 new file mode 100755 index 0000000..a5f4d4e --- /dev/null +++ b/testdata/corpus/seed_invalid_4 @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80b4-00c04fd430c8} \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_5 b/testdata/corpus/seed_invalid_5 new file mode 100755 index 0000000..a78e7ed --- /dev/null +++ b/testdata/corpus/seed_invalid_5 @@ -0,0 +1 @@ +{6ba7b810-9dad-11d1-80b4-00c04fd430c8}f \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_6 b/testdata/corpus/seed_invalid_6 new file mode 100755 index 0000000..f14ded5 --- /dev/null +++ b/testdata/corpus/seed_invalid_6 @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80b4-00c04fd430c800c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_7 b/testdata/corpus/seed_invalid_7 new file mode 100755 index 0000000..76e0980 --- /dev/null +++ b/testdata/corpus/seed_invalid_7 @@ -0,0 +1 @@ +ba7b8109dad11d180b400c04fd430c8} \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_8 b/testdata/corpus/seed_invalid_8 new file mode 100755 index 0000000..f89e744 --- /dev/null +++ b/testdata/corpus/seed_invalid_8 @@ -0,0 +1 @@ +6ba7b8109dad11d180b400c04fd430c86ba7b8109dad11d180b400c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_invalid_9 b/testdata/corpus/seed_invalid_9 new file mode 100755 index 0000000..80ad554 --- /dev/null +++ b/testdata/corpus/seed_invalid_9 @@ -0,0 +1 @@ +urn:uuid:{6ba7b810-9dad-11d1-80b4-00c04fd430c8} \ No newline at end of file diff --git a/testdata/corpus/seed_valid_BracedCanonical b/testdata/corpus/seed_valid_BracedCanonical new file mode 100755 index 0000000..23918e3 --- /dev/null +++ b/testdata/corpus/seed_valid_BracedCanonical @@ -0,0 +1 @@ +{6ba7b810-9dad-11d1-80b4-00c04fd430c8} \ No newline at end of file diff --git a/testdata/corpus/seed_valid_BracedHashlike b/testdata/corpus/seed_valid_BracedHashlike new file mode 100755 index 0000000..726e1df --- /dev/null +++ b/testdata/corpus/seed_valid_BracedHashlike @@ -0,0 +1 @@ +{6ba7b8109dad11d180b400c04fd430c8} \ No newline at end of file diff --git a/testdata/corpus/seed_valid_Canonical b/testdata/corpus/seed_valid_Canonical new file mode 100755 index 0000000..719471c --- /dev/null +++ b/testdata/corpus/seed_valid_Canonical @@ -0,0 +1 @@ +6ba7b810-9dad-11d1-80b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_valid_Hashlike b/testdata/corpus/seed_valid_Hashlike new file mode 100755 index 0000000..327f806 --- /dev/null +++ b/testdata/corpus/seed_valid_Hashlike @@ -0,0 +1 @@ +6ba7b8109dad11d180b400c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_valid_URNCanonical b/testdata/corpus/seed_valid_URNCanonical new file mode 100755 index 0000000..78981af --- /dev/null +++ b/testdata/corpus/seed_valid_URNCanonical @@ -0,0 +1 @@ +urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8 \ No newline at end of file diff --git a/testdata/corpus/seed_valid_URNHashlike b/testdata/corpus/seed_valid_URNHashlike new file mode 100755 index 0000000..089ec0c --- /dev/null +++ b/testdata/corpus/seed_valid_URNHashlike @@ -0,0 +1 @@ +urn:uuid:6ba7b8109dad11d180b400c04fd430c8 \ No newline at end of file diff --git a/uuid_test.go b/uuid_test.go index fa40280..b0cda6a 100644 --- a/uuid_test.go +++ b/uuid_test.go @@ -25,76 +25,120 @@ import ( "bytes" "fmt" "testing" - - . "gopkg.in/check.v1" ) -// Hook up gocheck into the "go test" runner. -func TestUUID(t *testing.T) { TestingT(t) } - -type testSuite struct{} - -var _ = Suite(&testSuite{}) - -func (s *testSuite) TestBytes(c *C) { - u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - bytes1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} - - c.Assert(bytes.Equal(u.Bytes(), bytes1), Equals, true) +func TestUUID(t *testing.T) { + t.Run("Bytes", testUUIDBytes) + t.Run("String", testUUIDString) + t.Run("Version", testUUIDVersion) + t.Run("Variant", testUUIDVariant) + t.Run("SetVersion", testUUIDSetVersion) + t.Run("SetVariant", testUUIDSetVariant) } -func (s *testSuite) TestString(c *C) { - c.Assert(NamespaceDNS.String(), Equals, "6ba7b810-9dad-11d1-80b4-00c04fd430c8") +func testUUIDBytes(t *testing.T) { + got := codecTestUUID.Bytes() + want := codecTestData + if !bytes.Equal(got, want) { + t.Errorf("%v.Bytes() = %x, want %x", codecTestUUID, got, want) + } } -func (s *testSuite) TestEqual(c *C) { - c.Assert(Equal(NamespaceDNS, NamespaceDNS), Equals, true) - c.Assert(Equal(NamespaceDNS, NamespaceURL), Equals, false) +func testUUIDString(t *testing.T) { + got := NamespaceDNS.String() + want := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + if got != want { + t.Errorf("%v.String() = %q, want %q", NamespaceDNS, got, want) + } } -func (s *testSuite) TestVersion(c *C) { +func testUUIDVersion(t *testing.T) { u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - c.Assert(u.Version(), Equals, V1) + if got, want := u.Version(), V1; got != want { + t.Errorf("%v.Version() == %d, want %d", u, got, want) + } } -func (s *testSuite) TestSetVersion(c *C) { - u := UUID{} - u.SetVersion(4) - c.Assert(u.Version(), Equals, V4) +func testUUIDVariant(t *testing.T) { + tests := []struct { + u UUID + want byte + }{ + { + u: UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + want: VariantNCS, + }, + { + u: UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + want: VariantRFC4122, + }, + { + u: UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + want: VariantMicrosoft, + }, + { + u: UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + want: VariantFuture, + }, + } + for _, tt := range tests { + if got := tt.u.Variant(); got != tt.want { + t.Errorf("%v.Variant() == %d, want %d", tt.u, got, tt.want) + } + } } -func (s *testSuite) TestVariant(c *C) { - u1 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - c.Assert(u1.Variant(), Equals, VariantNCS) - - u2 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - c.Assert(u2.Variant(), Equals, VariantRFC4122) - - u3 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - c.Assert(u3.Variant(), Equals, VariantMicrosoft) +func testUUIDSetVersion(t *testing.T) { + u := UUID{} + want := V4 + u.SetVersion(want) + if got := u.Version(); got != want { + t.Errorf("%v.Version() == %d after SetVersion(%d)", u, got, want) + } +} - u4 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - c.Assert(u4.Variant(), Equals, VariantFuture) +func testUUIDSetVariant(t *testing.T) { + variants := []byte{ + VariantNCS, + VariantRFC4122, + VariantMicrosoft, + VariantFuture, + } + for _, want := range variants { + u := UUID{} + u.SetVariant(want) + if got := u.Variant(); got != want { + t.Errorf("%v.Variant() == %d after SetVariant(%d)", u, got, want) + } + } } -func (s *testSuite) TestSetVariant(c *C) { - u := UUID{} - u.SetVariant(VariantNCS) - c.Assert(u.Variant(), Equals, VariantNCS) - u.SetVariant(VariantRFC4122) - c.Assert(u.Variant(), Equals, VariantRFC4122) - u.SetVariant(VariantMicrosoft) - c.Assert(u.Variant(), Equals, VariantMicrosoft) - u.SetVariant(VariantFuture) - c.Assert(u.Variant(), Equals, VariantFuture) +func TestEqual(t *testing.T) { + if !Equal(NamespaceDNS, NamespaceDNS) { + t.Errorf("NamespaceDNS (%v) != NamespaceDNS (%v)", NamespaceDNS, NamespaceDNS) + } + if Equal(NamespaceDNS, NamespaceURL) { + t.Errorf("NamespaceDNS (%v) == NamespaceURL (%v)", NamespaceDNS, NamespaceURL) + } } -func (s *testSuite) TestMust(c *C) { +func TestMust(t *testing.T) { + sentinel := fmt.Errorf("uuid: sentinel error") defer func() { - c.Assert(recover(), NotNil) + r := recover() + if r == nil { + t.Fatalf("did not panic, want %v", sentinel) + } + err, ok := r.(error) + if !ok { + t.Fatalf("panicked with %T, want error (%v)", r, sentinel) + } + if err != sentinel { + t.Fatalf("panicked with %v, want %v", err, sentinel) + } }() - Must(func() (UUID, error) { - return Nil, fmt.Errorf("uuid: expected error") - }()) + fn := func() (UUID, error) { + return Nil, sentinel + } + Must(fn()) }