diff options
Diffstat (limited to 'go/snowflake_test.go')
| -rw-r--r-- | go/snowflake_test.go | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/go/snowflake_test.go b/go/snowflake_test.go new file mode 100644 index 0000000..e69644c --- /dev/null +++ b/go/snowflake_test.go @@ -0,0 +1,340 @@ +package snowflake + +import ( + "encoding/json" + "testing" +) + +func TestNew(t *testing.T) { + s := New() + if s.IsZero() { + t.Error("New() returned zero Snowflake") + } +} + +func TestNewUnique(t *testing.T) { + seen := make(map[string]bool, 1000) + + for i := 0; i < 1000; i++ { + s := New() + + str := s.String() + if seen[str] { + t.Fatalf("duplicate ID generated: %s", str) + } + seen[str] = true + } +} + +func TestIsZero(t *testing.T) { + zero := Zero() + if !zero.IsZero() { + t.Error("Zero Snowflake should be zero") + } + + nonZero := New() + if nonZero.IsZero() { + t.Error("New Snowflake should not be zero") + } +} + +func TestStringRoundTrip(t *testing.T) { + original := New() + str := original.String() + parsed, err := FromString(str) + if err != nil { + t.Fatalf("FromString failed: %v", err) + } + + if parsed != original { + t.Errorf("round-trip mismatch: original=%+v, parsed=%+v", original, parsed) + } +} + +func TestStringRoundTripMany(t *testing.T) { + for i := 0; i < 100; i++ { + original := New() + + str := original.String() + parsed, err := FromString(str) + if err != nil { + t.Fatalf("iteration %d: FromString failed: %v", i, err) + } + if parsed != original { + t.Fatalf("iteration %d: round-trip mismatch", i) + } + } +} + +func TestFromStringInvalidChars(t *testing.T) { + _, err := FromString("!!invalid!!") + if err != ErrInvalidEncoding { + t.Errorf("expected ErrInvalidEncoding, got: %v", err) + } +} + +func TestFromStringEmpty(t *testing.T) { + s, err := FromString("") + if err != nil { + t.Errorf("unexpected error for empty string: %v", err) + } + if !s.IsZero() { + t.Error("empty string should produce zero Snowflake") + } +} + +func TestFromStringTooLong(t *testing.T) { + _, err := FromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + if err != ErrInvalidEncoding { + t.Errorf("expected ErrInvalidEncoding for overflow, got: %v", err) + } +} + +func TestHexString(t *testing.T) { + s := New() + hex := s.Hex() + + if len(hex) != IDByteSize*2 { + t.Errorf("expected hex length %d, got %d", IDByteSize*2, len(hex)) + } + + for _, c := range hex { + if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { + t.Errorf("invalid hex character: %c", c) + } + } +} + +func TestZeroString(t *testing.T) { + zero := Zero() + str := zero.String() + if str != "0" { + t.Errorf("Zero Snowflake should stringify to %q, got: %q", "0", str) + } + + parsed, err := FromString(str) + if err != nil { + t.Fatalf("FromString(%q) failed: %v", str, err) + } + if !parsed.IsZero() { + t.Error("FromString(Zero().String()) should round-trip to zero") + } +} + +func TestHexRoundTrip(t *testing.T) { + original := New() + hex := original.Hex() + parsed, err := FromHex(hex) + if err != nil { + t.Fatalf("FromHex failed: %v", err) + } + if parsed != original { + t.Error("hex round-trip mismatch") + } +} + +func TestFromHexInvalid(t *testing.T) { + _, err := FromHex("xyz") + if err == nil { + t.Error("expected error for invalid hex") + } +} + +func TestFromHexWrongLength(t *testing.T) { + _, err := FromHex("01") + if err != ErrInvalidIDLength { + t.Errorf("expected ErrInvalidIDLength, got: %v", err) + } +} + +func TestMarshalText(t *testing.T) { + s := New() + text, err := s.MarshalText() + if err != nil { + t.Fatalf("MarshalText failed: %v", err) + } + + var decoded Snowflake + err = decoded.UnmarshalText(text) + if err != nil { + t.Fatalf("UnmarshalText failed: %v", err) + } + + if decoded != s { + t.Error("text marshal/unmarshal mismatch") + } +} + +func TestUnmarshalTextInvalid(t *testing.T) { + var s Snowflake + err := s.UnmarshalText([]byte("!!!")) + if err == nil { + t.Error("expected error for invalid text") + } +} + +func TestMarshalJSON(t *testing.T) { + s := New() + data, err := s.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON failed: %v", err) + } + + var decoded Snowflake + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("json.Unmarshal failed: %v", err) + } + + if decoded != s { + t.Error("JSON marshal/unmarshal mismatch") + } +} + +func TestUnmarshalJSONMissingQuotes(t *testing.T) { + var s Snowflake + err := s.UnmarshalJSON([]byte(`invalid`)) + if err != ErrInvalidEncoding { + t.Errorf("expected ErrInvalidEncoding, got: %v", err) + } +} + +func TestUnmarshalJSONEmpty(t *testing.T) { + var s Snowflake + err := s.UnmarshalJSON([]byte(`""`)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !s.IsZero() { + t.Error("empty JSON string should produce zero Snowflake") + } +} + +func TestUnmarshalJSONInvalidInner(t *testing.T) { + var s Snowflake + err := s.UnmarshalJSON([]byte(`"!!!"`)) + if err != ErrInvalidEncoding { + t.Errorf("expected ErrInvalidEncoding for invalid inner content, got: %v", err) + } +} + +func TestDriverValue(t *testing.T) { + s := New() + val, err := s.Value() + if err != nil { + t.Fatalf("Value failed: %v", err) + } + + bytes, ok := val.([]byte) + if !ok { + t.Fatal("Value should return []byte") + } + + if len(bytes) != IDByteSize { + t.Errorf("expected byte length %d, got %d", IDByteSize, len(bytes)) + } +} + +func TestDriverScan(t *testing.T) { + original := New() + bytes := make([]byte, IDByteSize) + copy(bytes, original.bytes[:]) + + var s Snowflake + if err := s.Scan(bytes); err != nil { + t.Fatalf("Scan failed: %v", err) + } + + if s != original { + t.Error("Scan produced mismatched value") + } +} + +func TestDriverScanString(t *testing.T) { + original := New() + bytes := make([]byte, IDByteSize) + copy(bytes, original.bytes[:]) + + var s Snowflake + if err := s.Scan(string(bytes)); err != nil { + t.Fatalf("Scan(string) failed: %v", err) + } + + if s != original { + t.Error("Scan(string) produced mismatched value") + } +} + +func TestDriverScanNil(t *testing.T) { + var s Snowflake + err := s.Scan(nil) + if err != nil { + t.Fatalf("Scan(nil) failed: %v", err) + } + + if !s.IsZero() { + t.Error("Scan(nil) should produce zero Snowflake") + } +} + +func TestDriverScanWrongLength(t *testing.T) { + var s Snowflake + err := s.Scan([]byte{1, 2, 3}) + if err != ErrInvalidIDLength { + t.Errorf("expected ErrInvalidIDLength, got: %v", err) + } +} + +func TestDriverScanZeroBytes(t *testing.T) { + var s Snowflake + zeroBytes := make([]byte, IDByteSize) + err := s.Scan(zeroBytes) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !s.IsZero() { + t.Error("Scan with all-zero bytes should produce zero Snowflake") + } +} + +func TestDriverScanUnsupportedType(t *testing.T) { + var s Snowflake + err := s.Scan(42) + if err == nil { + t.Error("expected error for unsupported type") + } +} + +func TestJSONEmbedding(t *testing.T) { + type Wrapper struct { + Name string `json:"name"` + ID Snowflake `json:"id"` + Ref *Snowflake `json:"ref,omitempty"` + } + + s := New() + w := Wrapper{ + Name: "test", + ID: s, + Ref: &s, + } + + data, err := json.Marshal(&w) + if err != nil { + t.Fatalf("marshal failed: %v", err) + } + + var decoded Wrapper + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("unmarshal failed: %v", err) + } + + if decoded.ID != s { + t.Error("embedded ID mismatch") + } + + if decoded.Ref == nil || *decoded.Ref != s { + t.Error("embedded ref mismatch") + } +} |