From 6d9254e8e41ed59a0e829f14fbc9a53d05d38029 Mon Sep 17 00:00:00 2001 From: Azis Alvriyanto Date: Fri, 31 Jan 2025 01:44:24 +0700 Subject: [PATCH 1/4] test(marshal): add marshal/unmarshal tests --- marshal_test.go | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 marshal_test.go diff --git a/marshal_test.go b/marshal_test.go new file mode 100644 index 0000000..42df735 --- /dev/null +++ b/marshal_test.go @@ -0,0 +1,117 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/json" + "testing" +) + +func TestMarshalText(t *testing.T) { + u := UUID{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + expected := "01234567-89ab-cdef-fedc-ba9876543210" + + data, err := u.MarshalText() + if err != nil { + t.Fatalf("MarshalText failed: %v", err) + } + + if string(data) != expected { + t.Errorf("MarshalText() = %s; want %s", data, expected) + } +} + +func TestUnmarshalText(t *testing.T) { + var u UUID + input := []byte("01234567-89ab-cdef-fedc-ba9876543210") + expected := UUID{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + + err := u.UnmarshalText(input) + if err != nil { + t.Fatalf("UnmarshalText failed: %v", err) + } + + if u != expected { + t.Errorf("UnmarshalText() = %v; want %v", u, expected) + } +} + +func TestUnmarshalTextInvalidFormat(t *testing.T) { + var u UUID + input := []byte("invalid-uuid-format") + + err := u.UnmarshalText(input) + if err == nil { + t.Fatalf("UnmarshalText should have failed for invalid format") + } +} + +func TestMarshalBinary(t *testing.T) { + u := UUID{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + expected := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + + data, err := u.MarshalBinary() + if err != nil { + t.Fatalf("MarshalBinary failed: %v", err) + } + + if string(data) != string(expected) { + t.Errorf("MarshalBinary() = %v; want %v", data, expected) + } +} + +func TestUnmarshalBinary(t *testing.T) { + var u UUID + input := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + expected := UUID{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + + err := u.UnmarshalBinary(input) + if err != nil { + t.Fatalf("UnmarshalBinary failed: %v", err) + } + + if u != expected { + t.Errorf("UnmarshalBinary() = %v; want %v", u, expected) + } +} + +func TestUnmarshalBinaryInvalidLength(t *testing.T) { + var u UUID + input := []byte{0x01, 0x23, 0x45} // Invalid length + + err := u.UnmarshalBinary(input) + if err == nil { + t.Fatalf("UnmarshalBinary should have failed for invalid length") + } +} + +func TestJSONSerialization(t *testing.T) { + u := UUID{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + expected := `"01234567-89ab-cdef-fedc-ba9876543210"` + + jsonData, err := json.Marshal(u) + if err != nil { + t.Fatalf("JSON serialization failed: %v", err) + } + + if string(jsonData) != expected { + t.Errorf("JSON serialization = %s; want %s", jsonData, expected) + } +} + +func TestJSONDeserialization(t *testing.T) { + var u UUID + input := `"01234567-89ab-cdef-fedc-ba9876543210"` + expected := UUID{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10} + + err := json.Unmarshal([]byte(input), &u) + if err != nil { + t.Fatalf("JSON deserialization failed: %v", err) + } + + if u != expected { + t.Errorf("JSON deserialization = %v; want %v", u, expected) + } +} From 7016e7955e3fa6c34f4f6e6890d05401105cb193 Mon Sep 17 00:00:00 2001 From: Azis Alvriyanto Date: Fri, 31 Jan 2025 01:51:10 +0700 Subject: [PATCH 2/4] test(null): expand test coverage for NullUUID --- null_test.go | 98 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 20 deletions(-) diff --git a/null_test.go b/null_test.go index fe0fe8d..28d9c29 100644 --- a/null_test.go +++ b/null_test.go @@ -103,33 +103,47 @@ func TestNullUUIDMarshalText(t *testing.T) { func TestNullUUIDUnmarshalText(t *testing.T) { tests := []struct { - nullUUID NullUUID + name string + data []byte + expected NullUUID + expectedErr bool }{ { - nullUUID: NullUUID{}, + name: "null text", + data: []byte("null"), + expected: NullUUID{Valid: false}, + expectedErr: true, // "null" is not a valid UUID format }, { - nullUUID: NullUUID{ - UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), - Valid: true, - }, + name: "valid UUID", + data: []byte("12345678-abcd-1234-abcd-0123456789ab"), + expected: NullUUID{UUID: MustParse("12345678-abcd-1234-abcd-0123456789ab"), Valid: true}, + expectedErr: false, + }, + { + name: "invalid text", + data: []byte("invalid"), + expected: NullUUID{Valid: false}, + expectedErr: true, }, } + for _, test := range tests { - var uText []byte - var uErr error - nuText, nuErr := test.nullUUID.MarshalText() - if test.nullUUID.Valid { - uText, uErr = test.nullUUID.UUID.MarshalText() - } else { - uText = []byte("null") - } - if nuErr != uErr { - t.Errorf("expected error %e, got %e", nuErr, uErr) - } - if !bytes.Equal(nuText, uText) { - t.Errorf("expected text data %s, got %s", string(nuText), string(uText)) - } + t.Run(test.name, func(t *testing.T) { + var nu NullUUID + err := nu.UnmarshalText(test.data) + if (err != nil) != test.expectedErr { + t.Errorf("expected error %v, got %v", test.expectedErr, err) + } + if !test.expectedErr { + if nu.Valid != test.expected.Valid { + t.Errorf("expected Valid %v, got %v", test.expected.Valid, nu.Valid) + } + if nu.Valid && nu.UUID != test.expected.UUID { + t.Errorf("expected UUID %v, got %v", test.expected.UUID, nu.UUID) + } + } + }) } } @@ -165,6 +179,50 @@ func TestNullUUIDMarshalBinary(t *testing.T) { } } +func TestNullUUIDUnmarshalBinary(t *testing.T) { + validUUID := MustParse("12345678-abcd-1234-abcd-0123456789ab") + validData := validUUID[:] + invalidData := []byte{1, 2, 3} + + tests := []struct { + name string + data []byte + expected NullUUID + expectedErr bool + }{ + { + name: "valid data", + data: validData, + expected: NullUUID{UUID: validUUID, Valid: true}, + expectedErr: false, + }, + { + name: "invalid length", + data: invalidData, + expected: NullUUID{}, + expectedErr: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var nu NullUUID + err := nu.UnmarshalBinary(test.data) + if (err != nil) != test.expectedErr { + t.Errorf("expected error %v, got %v", test.expectedErr, err) + } + if !test.expectedErr { + if nu.Valid != test.expected.Valid { + t.Errorf("expected Valid %v, got %v", test.expected.Valid, nu.Valid) + } + if nu.Valid && nu.UUID != test.expected.UUID { + t.Errorf("expected UUID %v, got %v", test.expected.UUID, nu.UUID) + } + } + }) + } +} + func TestNullUUIDMarshalJSON(t *testing.T) { jsonNull, _ := json.Marshal(nil) jsonUUID, _ := json.Marshal(MustParse("12345678-abcd-1234-abcd-0123456789ab")) From 68679d6d4ee56bdc513a5dc3c1ac57362ea2c648 Mon Sep 17 00:00:00 2001 From: Azis Alvriyanto Date: Fri, 31 Jan 2025 02:11:01 +0700 Subject: [PATCH 3/4] test(time): add test for Time and ClockSequence method --- time_test.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/time_test.go b/time_test.go index 46354a4..6c93619 100644 --- a/time_test.go +++ b/time_test.go @@ -42,3 +42,77 @@ func TestGetTime(t *testing.T) { }) } } + +func TestClockSequenceInitialization(t *testing.T) { + // Backup and reset global state + timeMu.Lock() + origSeq := clockSeq + clockSeq = 0 // Force initialization + timeMu.Unlock() + defer func() { + timeMu.Lock() + clockSeq = origSeq + timeMu.Unlock() + }() + + // First call initializes the sequence + seq := ClockSequence() + if seq == 0 { + t.Error("ClockSequence() should not return 0 after initialization") + } + + // Ensure the sequence is within 14-bit mask + if seq&0xc000 != 0 { + t.Errorf("ClockSequence() = %x, expected 14-bit value (mask 0x3fff)", seq) + } + + // Subsequent call should return the same sequence + seq2 := ClockSequence() + if seq2 != seq { + t.Errorf("Expected sequence %x, got %x", seq, seq2) + } +} + +func TestTime(t *testing.T) { + tests := []struct { + name string + uuid UUID + version int + want Time + }{ + { + name: "Version 6", + uuid: UUID{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0x6D, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + version: 6, + want: Time((0x12345678 << 28) | (0x9ABC << 12) | 0xDEF), + }, + { + name: "Version 7", + uuid: UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + version: 7, + want: Time(g1582ns100), + }, + { + name: "Default Version", + uuid: UUID{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0x1D, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + version: 1, + want: Time(int64(0x12345678) | (int64(0x9ABC) << 32) | (int64(0xDEF) << 48)), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.uuid.Time(); got != tt.want { + t.Errorf("UUID.Time() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestClockSequence(t *testing.T) { + uuid := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + expected := 0x1234 & 0x3fff + if got := uuid.ClockSequence(); got != expected { + t.Errorf("ClockSequence() = %x, want %x", got, expected) + } +} From 7c40a065a666f02a014584fae291b3860126f6ae Mon Sep 17 00:00:00 2001 From: Azis Alvriyanto Date: Fri, 31 Jan 2025 02:20:47 +0700 Subject: [PATCH 4/4] test(util): add test for randomBits panic on error --- util_test.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 util_test.go diff --git a/util_test.go b/util_test.go new file mode 100644 index 0000000..e9d2fb6 --- /dev/null +++ b/util_test.go @@ -0,0 +1,57 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "errors" + "testing" +) + +// mockReader is a mock implementation of io.Reader for testing +type mockReader struct { + data []byte // Data to be read + err error // Error to return during read +} + +func (m *mockReader) Read(p []byte) (n int, err error) { + if m.err != nil { + return 0, m.err + } + n = copy(p, m.data) + return n, nil +} + +// TestRandomBits tests the randomBits function +func TestRandomBits(t *testing.T) { + originalRander := rander + defer func() { rander = originalRander }() + + t.Run("fills slice with random data", func(t *testing.T) { + mockData := []byte{0x01, 0x02, 0x03, 0x04} + rander = &mockReader{data: mockData} + + b := make([]byte, len(mockData)) + randomBits(b) + + if !bytes.Equal(b, mockData) { + t.Errorf("expected %v, got %v", mockData, b) + } + }) + + t.Run("panics on read error", func(t *testing.T) { + rander = &mockReader{err: errors.New("read error")} + + defer func() { + if r := recover(); r == nil { + t.Error("expected panic, but did not occur") + } else if errMsg, ok := r.(string); !ok || errMsg != "read error" { + t.Errorf("expected panic with message 'read error', got %v", r) + } + }() + + randomBits(make([]byte, 4)) + }) +}