package cart import ( "encoding/json" "fmt" "testing" ) // TestNewCartIdUniqueness generates many ids and checks for collisions. func TestNewCartIdUniqueness(t *testing.T) { const n = 20000 seen := make(map[string]struct{}, n) for i := 0; i < n; i++ { id, err := NewCartId() if err != nil { t.Fatalf("NewCartId error: %v", err) } s := id.String() if _, exists := seen[s]; exists { t.Fatalf("duplicate id encountered: %s", s) } seen[s] = struct{}{} if s == "" { t.Fatalf("empty string representation for id %d", id) } if len(s) > 11 { t.Fatalf("encoded id length exceeds 11 chars: %s (%d)", s, len(s)) } if id == 0 { // We force regeneration on zero, extremely unlikely but test guards intent. t.Fatalf("zero id generated (should be regenerated)") } } } // TestParseCartIdRoundTrip ensures parse -> string -> parse is stable. func TestParseCartIdRoundTrip(t *testing.T) { id := MustNewCartId() txt := id.String() parsed, ok := ParseCartId(txt) if !ok { t.Fatalf("ParseCartId failed for valid text %q", txt) } if parsed != id { t.Fatalf("round trip mismatch: original=%d parsed=%d txt=%s", id, parsed, txt) } } // TestParseCartIdInvalid covers invalid inputs. func TestParseCartIdInvalid(t *testing.T) { invalid := []string{ "", // empty " ", // space "01234567890abc", // >11 chars "!!!!", // invalid chars "-underscore-", // invalid chars "abc_def", // underscore invalid for base62 "0123456789ABCD", // 14 chars } for _, s := range invalid { if _, ok := ParseCartId(s); ok { t.Fatalf("expected parse failure for %q", s) } } } // TestMustParseCartIdPanics verifies panic behavior for invalid input. func TestMustParseCartIdPanics(t *testing.T) { defer func() { if r := recover(); r == nil { t.Fatalf("expected panic for invalid MustParseCartId input") } }() _ = MustParseCartId("not*base62") } // TestJSONMarshalUnmarshalCartId verifies JSON round trip. func TestJSONMarshalUnmarshalCartId(t *testing.T) { id := MustNewCartId() data, err := json.Marshal(struct { Cart CartId `json:"cart"` }{Cart: id}) if err != nil { t.Fatalf("marshal error: %v", err) } var out struct { Cart CartId `json:"cart"` } if err := json.Unmarshal(data, &out); err != nil { t.Fatalf("unmarshal error: %v", err) } if out.Cart != id { t.Fatalf("JSON round trip mismatch: have %d got %d", id, out.Cart) } } // TestBase62LengthBound checks worst-case length (near max uint64). func TestBase62LengthBound(t *testing.T) { // Largest uint64 const maxU64 = ^uint64(0) s := encodeBase62(maxU64) if len(s) > 11 { t.Fatalf("max uint64 encoded length > 11: %d (%s)", len(s), s) } dec, ok := decodeBase62(s) if !ok || dec != maxU64 { t.Fatalf("decode failed for max uint64: ok=%v dec=%d want=%d", ok, dec, maxU64) } } // TestZeroEncoding ensures zero value encodes to "0" and parses back. func TestZeroEncoding(t *testing.T) { if s := encodeBase62(0); s != "0" { t.Fatalf("encodeBase62(0) expected '0', got %q", s) } v, ok := decodeBase62("0") if !ok || v != 0 { t.Fatalf("decodeBase62('0') failed: ok=%v v=%d", ok, v) } if _, ok := ParseCartId("0"); !ok { t.Fatalf("ParseCartId(\"0\") should succeed") } } // TestSequentialParse ensures sequentially generated ids parse correctly. func TestSequentialParse(t *testing.T) { for i := 0; i < 1000; i++ { id := MustNewCartId() txt := id.String() parsed, ok := ParseCartId(txt) if !ok || parsed != id { t.Fatalf("sequential parse mismatch: idx=%d orig=%d parsed=%d txt=%s", i, id, parsed, txt) } } } // BenchmarkNewCartId measures generation performance. func BenchmarkNewCartId(b *testing.B) { for i := 0; i < b.N; i++ { if _, err := NewCartId(); err != nil { b.Fatalf("NewCartId error: %v", err) } } } // BenchmarkEncodeBase62 measures encoding performance. func BenchmarkEncodeBase62(b *testing.B) { // Precompute sample values samples := make([]uint64, 1024) for i := range samples { // Spread bits without crypto randomness overhead samples[i] = (uint64(i) << 53) ^ (uint64(i) * 0x9E3779B185EBCA87) } b.ResetTimer() var sink string for i := 0; i < b.N; i++ { sink = encodeBase62(samples[i%len(samples)]) } _ = sink } // BenchmarkDecodeBase62 measures decoding performance. func BenchmarkDecodeBase62(b *testing.B) { encoded := make([]string, 1024) for i := range encoded { encoded[i] = encodeBase62((uint64(i) << 32) | uint64(i)) } b.ResetTimer() var sum uint64 for i := 0; i < b.N; i++ { v, ok := decodeBase62(encoded[i%len(encoded)]) if !ok { b.Fatalf("decode failure for %s", encoded[i%len(encoded)]) } sum ^= v } _ = sum } // ExampleCartIdString documents usage of CartId string form. func ExampleCartId_string() { id := MustNewCartId() fmt.Println(len(id.String()) <= 11) // outputs true // Output: true }