fix(selector): safe type assertion, clean up debug logging, add doc comments and 64 tests

Replace bare type assertion in ParallelStrategy with comma-ok check to
prevent panic on non-Node inputs. Downgrade noisy Infof hash-selection
log to Tracef and remove Chinese-language debug output. Add doc comments
to all exported symbols in weighted.go.
This commit is contained in:
ginuerzh
2026-05-25 23:38:35 +08:00
parent 18f39f940b
commit aabebd047b
9 changed files with 992 additions and 5 deletions
+130
View File
@@ -0,0 +1,130 @@
package selector
import (
"testing"
)
func TestRandomWeighted_Empty(t *testing.T) {
rw := NewRandomWeighted[int]()
if v := rw.Next(); v != 0 {
t.Fatalf("expected zero value, got %d", v)
}
}
func TestRandomWeighted_Single(t *testing.T) {
rw := NewRandomWeighted[int]()
rw.Add(42, 10)
for i := 0; i < 100; i++ {
if v := rw.Next(); v != 42 {
t.Fatalf("expected 42, got %d", v)
}
}
}
func TestRandomWeighted_EqualWeights(t *testing.T) {
rw := NewRandomWeighted[int]()
rw.Add(1, 1)
rw.Add(2, 1)
rw.Add(3, 1)
counts := make(map[int]int)
const n = 3000
for i := 0; i < n; i++ {
counts[rw.Next()]++
}
for _, item := range []int{1, 2, 3} {
if counts[item] < n/3/2 {
t.Fatalf("item %d underrepresented: %d/%d", item, counts[item], n)
}
}
}
func TestRandomWeighted_WeightedDistribution(t *testing.T) {
rw := NewRandomWeighted[string]()
rw.Add("heavy", 99)
rw.Add("light", 1)
heavyCount := 0
const n = 5000
for i := 0; i < n; i++ {
if rw.Next() == "heavy" {
heavyCount++
}
}
// ~99% should be heavy
if heavyCount < int(float64(n)*0.95) {
t.Fatalf("heavy underrepresented: %d/%d", heavyCount, n)
}
}
func TestRandomWeighted_ZeroWeight(t *testing.T) {
rw := NewRandomWeighted[int]()
rw.Add(1, 0)
rw.Add(2, 0)
// sum=0, should return zero value
if v := rw.Next(); v != 0 {
t.Fatalf("expected zero value with sum=0, got %d", v)
}
}
func TestRandomWeighted_Reset(t *testing.T) {
rw := NewRandomWeighted[int]()
rw.Add(1, 10)
rw.Add(2, 20)
rw.Reset()
if v := rw.Next(); v != 0 {
t.Fatalf("expected zero value after reset, got %d", v)
}
// Can add again after reset
rw.Add(3, 1)
if v := rw.Next(); v != 3 {
t.Fatalf("expected 3 after re-add, got %d", v)
}
}
func TestRandomWeighted_MultipleWeights(t *testing.T) {
rw := NewRandomWeighted[int]()
rw.Add(0, 1)
rw.Add(1, 2)
rw.Add(2, 3)
// Total weight = 6
counts := make(map[int]int)
const n = 6000
for i := 0; i < n; i++ {
counts[rw.Next()]++
}
// Item 2 should appear roughly 2x more than item 0
ratio := float64(counts[2]) / float64(counts[0])
if ratio < 1.5 || ratio > 3.5 {
t.Fatalf("expected ratio ~2.0 for item2/item0, got %.2f (counts: %v)", ratio, counts)
}
}
func TestRandomWeighted_StringItems(t *testing.T) {
rw := NewRandomWeighted[string]()
rw.Add("a", 1)
rw.Add("b", 1)
v := rw.Next()
if v != "a" && v != "b" {
t.Fatalf("expected 'a' or 'b', got %q", v)
}
}
func TestRandomWeighted_StructItems(t *testing.T) {
type item struct{ Name string }
rw := NewRandomWeighted[item]()
rw.Add(item{Name: "x"}, 1)
rw.Add(item{Name: "y"}, 1)
v := rw.Next()
if v.Name != "x" && v.Name != "y" {
t.Fatalf("unexpected item: %+v", v)
}
}