// Copyright (C) 2013-2018 by Maxim Bublis // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package uuid import ( "bytes" "fmt" "testing" "time" ) func TestUUID(t *testing.T) { t.Run("IsNil", testUUIDIsNil) t.Run("Bytes", testUUIDBytes) t.Run("String", testUUIDString) t.Run("Version", testUUIDVersion) t.Run("Variant", testUUIDVariant) t.Run("SetVersion", testUUIDSetVersion) t.Run("SetVariant", testUUIDSetVariant) t.Run("Format", testUUIDFormat) } func testUUIDIsNil(t *testing.T) { u := UUID{} got := u.IsNil() want := true if got != want { t.Errorf("%v.IsNil() = %t, want %t", u, got, want) } } 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 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 testUUIDVersion(t *testing.T) { u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} if got, want := u.Version(), V1; got != want { t.Errorf("%v.Version() == %d, want %d", u, got, want) } } 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 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) } } 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 testUUIDFormat(t *testing.T) { val := Must(FromString("12345678-90ab-cdef-1234-567890abcdef")) tests := []struct { u UUID f string want string }{ {u: val, f: "%s", want: "12345678-90ab-cdef-1234-567890abcdef"}, {u: val, f: "%S", want: "12345678-90AB-CDEF-1234-567890ABCDEF"}, {u: val, f: "%q", want: `"12345678-90ab-cdef-1234-567890abcdef"`}, {u: val, f: "%x", want: "1234567890abcdef1234567890abcdef"}, {u: val, f: "%X", want: "1234567890ABCDEF1234567890ABCDEF"}, {u: val, f: "%v", want: "12345678-90ab-cdef-1234-567890abcdef"}, {u: val, f: "%+v", want: "12345678-90ab-cdef-1234-567890abcdef"}, {u: val, f: "%#v", want: "[16]uint8{0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}"}, {u: val, f: "%T", want: "uuid.UUID"}, {u: val, f: "%t", want: "%!t(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%b", want: "%!b(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%c", want: "%!c(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%d", want: "%!d(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%e", want: "%!e(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%E", want: "%!E(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%f", want: "%!f(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%F", want: "%!F(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%g", want: "%!g(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%G", want: "%!G(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%o", want: "%!o(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, {u: val, f: "%U", want: "%!U(uuid.UUID=12345678-90ab-cdef-1234-567890abcdef)"}, } for _, tt := range tests { got := fmt.Sprintf(tt.f, tt.u) if tt.want != got { t.Errorf(`Format("%s") got %s, want %s`, tt.f, got, tt.want) } } } func TestMust(t *testing.T) { sentinel := fmt.Errorf("uuid: sentinel error") defer func() { 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) } }() fn := func() (UUID, error) { return Nil, sentinel } Must(fn()) } func TestTimeFromTimestamp(t *testing.T) { tests := []struct { t Timestamp want time.Time }{ // a zero timestamp represents October 15, 1582 at midnight UTC {t: Timestamp(0), want: time.Date(1582, 10, 15, 0, 0, 0, 0, time.UTC)}, // a one value is 100ns later {t: Timestamp(1), want: time.Date(1582, 10, 15, 0, 0, 0, 100, time.UTC)}, // 10 million 100ns intervals later is one second {t: Timestamp(10000000), want: time.Date(1582, 10, 15, 0, 0, 1, 0, time.UTC)}, {t: Timestamp(60 * 10000000), want: time.Date(1582, 10, 15, 0, 1, 0, 0, time.UTC)}, {t: Timestamp(60 * 60 * 10000000), want: time.Date(1582, 10, 15, 1, 0, 0, 0, time.UTC)}, {t: Timestamp(24 * 60 * 60 * 10000000), want: time.Date(1582, 10, 16, 0, 0, 0, 0, time.UTC)}, {t: Timestamp(365 * 24 * 60 * 60 * 10000000), want: time.Date(1583, 10, 15, 0, 0, 0, 0, time.UTC)}, // maximum timestamp value in a UUID is the year 5236 {t: Timestamp(uint64(1<<60 - 1)), want: time.Date(5236, 03, 31, 21, 21, 0, 684697500, time.UTC)}, } for _, tt := range tests { got, _ := tt.t.Time() if !got.Equal(tt.want) { t.Errorf("%v.Time() == %v, want %v", tt.t, got, tt.want) } } } func TestTimestampFromV1(t *testing.T) { tests := []struct { u UUID want Timestamp wanterr bool }{ {u: Must(NewV4()), wanterr: true}, {u: Must(FromString("00000000-0000-1000-0000-000000000000")), want: 0}, {u: Must(FromString("424f137e-a2aa-11e8-98d0-529269fb1459")), want: 137538640775418750}, {u: Must(FromString("ffffffff-ffff-1fff-ffff-ffffffffffff")), want: Timestamp(1<<60 - 1)}, } for _, tt := range tests { got, goterr := TimestampFromV1(tt.u) if tt.wanterr && goterr == nil { t.Errorf("TimestampFromV1(%v) want error, got %v", tt.u, got) } else if tt.want != got { t.Errorf("TimestampFromV1(%v) got %v, want %v", tt.u, got, tt.want) } } } func TestTimestampFromV6(t *testing.T) { tests := []struct { u UUID want Timestamp wanterr bool }{ {u: Must(NewV1()), wanterr: true}, {u: Must(FromString("00000000-0000-6000-0000-000000000000")), want: 0}, {u: Must(FromString("1ec06cff-e9b1-621c-8627-ba3fd7e551c9")), want: 138493178941215260}, {u: Must(FromString("ffffffff-ffff-6fff-ffff-ffffffffffff")), want: Timestamp(1<<60 - 1)}, } for _, tt := range tests { got, err := TimestampFromV6(tt.u) switch { case tt.wanterr && err == nil: t.Errorf("TimestampFromV6(%v) want error, got %v", tt.u, got) case tt.want != got: t.Errorf("TimestampFromV6(%v) got %v, want %v", tt.u, got, tt.want) } } }