package main import ( "crypto/rand" "encoding/binary" "fmt" mrand "math/rand" "testing" ) // TestEncodeDecodeBase62RoundTrip verifies encodeBase62/decodeBase62 are inverse. func TestEncodeDecodeBase62RoundTrip(t *testing.T) { mrand.Seed(42) for i := 0; i < 1000; i++ { // Random 64-bit value v := mrand.Uint64() s := encodeBase62(v) dec, ok := decodeBase62(s) if !ok { t.Fatalf("decodeBase62 failed for %d encoded=%s", v, s) } if dec != v { t.Fatalf("round trip mismatch: have %d got %d (encoded=%s)", v, dec, s) } } // Explicit zero test if s := encodeBase62(0); s != "0" { t.Fatalf("expected encodeBase62(0) == \"0\", got %q", s) } if v, ok := decodeBase62("0"); !ok || v != 0 { t.Fatalf("decodeBase62(0) unexpected result v=%d ok=%v", v, ok) } } // TestNewCartIDUniqueness generates a number of IDs and checks for duplicates. func TestNewCartIDUniqueness(t *testing.T) { const n = 10000 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 CartID generated: %s", s) } seen[s] = struct{}{} if id.IsZero() { t.Fatalf("NewCartID returned zero value") } } } // TestParseCartIDValidation tests parsing of valid and invalid base62 strings. func TestParseCartIDValidation(t *testing.T) { id, err := NewCartID() if err != nil { t.Fatalf("NewCartID error: %v", err) } parsed, ok := ParseCartID(id.String()) if !ok { t.Fatalf("ParseCartID failed for valid id %s", id) } if parsed.raw != id.raw { t.Fatalf("parsed raw mismatch: %d vs %d", parsed.raw, id.raw) } if _, ok := ParseCartID(""); ok { t.Fatalf("expected empty string to be invalid") } // Invalid char ('-') if _, ok := ParseCartID("abc-123"); ok { t.Fatalf("expected invalid chars to fail parse") } // Overly long ( >16 ) if _, ok := ParseCartID("1234567890abcdefg"); ok { t.Fatalf("expected overly long string to fail parse") } } // TestFallbackDeterminism ensures fallback hashing is deterministic. func TestFallbackDeterminism(t *testing.T) { inputs := []string{ "legacy-cart-1", "legacy-cart-2", "UPPER_lower_123", "🚀unicode", // unicode bytes (will hash byte sequence) } for _, in := range inputs { a := FallbackFromString(in) b := FallbackFromString(in) if a.raw != b.raw || a.String() != b.String() { t.Fatalf("fallback mismatch for %q: %+v vs %+v", in, a, b) } } // Distinct inputs should almost always differ; sample check a := FallbackFromString("distinct-A") b := FallbackFromString("distinct-B") if a.raw == b.raw { t.Fatalf("unexpected identical fallback hashes for distinct inputs") } } // TestCanonicalizeIncomingBehavior covers main control flow branches. func TestCanonicalizeIncomingBehavior(t *testing.T) { // Empty => new id id1, generated, err := CanonicalizeIncoming("") if err != nil || !generated || id1.IsZero() { t.Fatalf("CanonicalizeIncoming empty failed: id=%v gen=%v err=%v", id1, generated, err) } // Valid base62 => parse; no generation id2, gen2, err := CanonicalizeIncoming(id1.String()) if err != nil || gen2 || id2.raw != id1.raw { t.Fatalf("CanonicalizeIncoming parse mismatch: id2=%v gen2=%v err=%v", id2, gen2, err) } // Legacy-like random containing invalid chars -> fallback fallbackInput := "legacy\x00\x00padding" id3, gen3, err := CanonicalizeIncoming(fallbackInput) if err != nil || gen3 { t.Fatalf("CanonicalizeIncoming fallback unexpected: id3=%v gen3=%v err=%v", id3, gen3, err) } // Deterministic fallback id4, _, _ := CanonicalizeIncoming(fallbackInput) if id3.raw != id4.raw { t.Fatalf("fallback canonicalization not deterministic") } } // TestUpgradeLegacyCartId ensures mapping of old CartId is stable. func TestUpgradeLegacyCartId(t *testing.T) { var legacy CartId copy(legacy[:], []byte("legacy-123456789")) // 15 bytes + padding up1 := UpgradeLegacyCartId(legacy) up2 := UpgradeLegacyCartId(legacy) if up1.raw != up2.raw { t.Fatalf("UpgradeLegacyCartId not deterministic: %v vs %v", up1, up2) } if up1.String() != up2.String() { t.Fatalf("UpgradeLegacyCartId string mismatch: %s vs %s", up1, up2) } } // BenchmarkNewCartID gives a rough idea of generation cost. func BenchmarkNewCartID(b *testing.B) { for i := 0; i < b.N; i++ { if _, err := NewCartID(); err != nil { b.Fatalf("error: %v", err) } } } // BenchmarkEncodeBase62 measures encode speed in isolation. func BenchmarkEncodeBase62(b *testing.B) { // Random sample of values samples := make([]uint64, 1024) for i := range samples { var buf [8]byte if _, err := rand.Read(buf[:]); err != nil { b.Fatalf("rand: %v", err) } samples[i] = binary.BigEndian.Uint64(buf[:]) } b.ResetTimer() var sink string for i := 0; i < b.N; i++ { sink = encodeBase62(samples[i%len(samples)]) } _ = sink } // BenchmarkDecodeBase62 measures decode speed. func BenchmarkDecodeBase62(b *testing.B) { // Pre-encode 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 failed") } sum ^= v } _ = sum } // TestLookupNDeterminism (ring integration smoke test) ensures LookupN // returns distinct hosts and stable ordering for a fixed ring. func TestLookupNDeterminism(t *testing.T) { rb := NewRingBuilder().WithEpoch(1).WithVnodesPerHost(8).WithHosts([]string{"a", "b", "c"}) ring := rb.Build() if ring.Empty() { t.Fatalf("expected non-empty ring") } id := MustNewCartID() owners1 := ring.LookupN(id.Raw(), 3) owners2 := ring.LookupN(id.Raw(), 3) if len(owners1) != len(owners2) { t.Fatalf("LookupN length mismatch") } for i := range owners1 { if owners1[i].Host != owners2[i].Host { t.Fatalf("LookupN ordering instability at %d: %v vs %v", i, owners1[i], owners2[i]) } } // Distinct host constraint seen := map[string]struct{}{} for _, v := range owners1 { if _, ok := seen[v.Host]; ok { t.Fatalf("duplicate host in LookupN result: %v", owners1) } seen[v.Host] = struct{}{} } } // TestRingFingerprintChanges ensures fingerprint updates with membership changes. func TestRingFingerprintChanges(t *testing.T) { b1 := NewRingBuilder().WithEpoch(1).WithHosts([]string{"node1", "node2"}) r1 := b1.Build() b2 := NewRingBuilder().WithEpoch(2).WithHosts([]string{"node1", "node2", "node3"}) r2 := b2.Build() if r1.Fingerprint() == r2.Fingerprint() { t.Fatalf("expected differing fingerprints after host set change") } } // TestRingDiffHosts verifies added/removed host detection. func TestRingDiffHosts(t *testing.T) { r1 := NewRingBuilder().WithEpoch(1).WithHosts([]string{"a", "b"}).Build() r2 := NewRingBuilder().WithEpoch(2).WithHosts([]string{"b", "c"}).Build() added, removed := r1.DiffHosts(r2) if fmt.Sprintf("%v", added) != "[c]" { t.Fatalf("expected added [c], got %v", added) } if fmt.Sprintf("%v", removed) != "[a]" { t.Fatalf("expected removed [a], got %v", removed) } } // TestRingLookupConsistency ensures direct Lookup and LookupID are aligned. func TestRingLookupConsistency(t *testing.T) { ring := NewRingBuilder().WithEpoch(1).WithHosts([]string{"alpha", "beta"}).WithVnodesPerHost(4).Build() id, _ := ParseCartID("1") if id.IsZero() { t.Fatalf("expected parsed id non-zero") } v1 := ring.Lookup(id.Raw()) v2 := ring.LookupID(id) if v1.Host != v2.Host || v1.Hash != v2.Hash { t.Fatalf("Lookup vs LookupID mismatch: %+v vs %+v", v1, v2) } }