package sortedset import ( "testing" ) func checkOrder(t *testing.T, nodes []*SortedSetNode[string, int64, string], expectedOrder []string) { if len(expectedOrder) != len(nodes) { t.Errorf("nodes does not contain %d elements", len(expectedOrder)) } for i := 0; i < len(expectedOrder); i++ { if nodes[i].Key() != expectedOrder[i] { t.Errorf("nodes[%d] is %q, but the expected key is %q", i, nodes[i].Key(), expectedOrder[i]) } } } func checkIterByRankRange(t *testing.T, sortedset *SortedSet[string, int64, string], start int, end int, expectedOrder []string) { var keys []string // check nil callback should do nothing sortedset.IterFuncRangeByRank(start, end, nil) sortedset.IterFuncRangeByRank(start, end, func(key string, _ int64, _ string) bool { keys = append(keys, key) return true }) if len(expectedOrder) != len(keys) { t.Errorf("keys does not contain %d elements", len(expectedOrder)) } for i := 0; i < len(expectedOrder); i++ { if keys[i] != expectedOrder[i] { t.Errorf("keys[%d] is %q, but the expected key is %q", i, keys[i], expectedOrder[i]) } } // check return early if len(expectedOrder) < 1 { return } // reset data keys = []string{} var i int sortedset.IterFuncRangeByRank(start, end, func(key string, _ int64, _ string) bool { keys = append(keys, key) i++ // return early return i < len(expectedOrder)-1 }) if len(expectedOrder)-1 != len(keys) { t.Errorf("keys does not contain %d elements", len(expectedOrder)-1) } for i := 0; i < len(expectedOrder)-1; i++ { if keys[i] != expectedOrder[i] { t.Errorf("keys[%d] is %q, but the expected key is %q", i, keys[i], expectedOrder[i]) } } } func checkRankRangeIterAndOrder(t *testing.T, sortedset *SortedSet[string, int64, string], start int, end int, remove bool, expectedOrder []string) { checkIterByRankRange(t, sortedset, start, end, expectedOrder) nodes := sortedset.GetRangeByRank(start, end, remove) checkOrder(t, nodes, expectedOrder) } func TestCase1(t *testing.T) { sortedset := New[string, int64, string]() sortedset.AddOrUpdate("a", 89, "Kelly") sortedset.AddOrUpdate("b", 100, "Staley") sortedset.AddOrUpdate("c", 100, "Jordon") sortedset.AddOrUpdate("d", -321, "Park") sortedset.AddOrUpdate("e", 101, "Albert") sortedset.AddOrUpdate("f", 99, "Lyman") sortedset.AddOrUpdate("g", 99, "Singleton") sortedset.AddOrUpdate("h", 70, "Audrey") sortedset.AddOrUpdate("e", 99, "ntrnrt") sortedset.Remove("b") node := sortedset.GetByRank(3, false) if node == nil || node.Key() != "a" { t.Error("GetByRank() does not return expected value `a`") } node = sortedset.GetByRank(-3, false) if node == nil || node.Key() != "f" { t.Error("GetByRank() does not return expected value `f`") } // get all nodes since the first one to last one checkRankRangeIterAndOrder(t, sortedset, 1, -1, false, []string{"d", "h", "a", "e", "f", "g", "c"}) // get & remove the 2nd/3rd nodes in reserve order checkRankRangeIterAndOrder(t, sortedset, -2, -3, true, []string{"g", "f"}) // get all nodes since the last one to first one checkRankRangeIterAndOrder(t, sortedset, -1, 1, false, []string{"c", "e", "a", "h", "d"}) } func TestCase2(t *testing.T) { // create a new set sortedset := New[string, int64, string]() // fill in new node sortedset.AddOrUpdate("a", 89, "Kelly") sortedset.AddOrUpdate("b", 100, "Staley") sortedset.AddOrUpdate("c", 100, "Jordon") sortedset.AddOrUpdate("d", -321, "Park") sortedset.AddOrUpdate("e", 101, "Albert") sortedset.AddOrUpdate("f", 99, "Lyman") sortedset.AddOrUpdate("g", 99, "Singleton") sortedset.AddOrUpdate("h", 70, "Audrey") // update an existing node sortedset.AddOrUpdate("e", 99, "ntrnrt") // remove node sortedset.Remove("b") nodes := sortedset.GetRangeByScore(-500, 500, nil) checkOrder(t, nodes, []string{"d", "h", "a", "e", "f", "g", "c"}) nodes = sortedset.GetRangeByScore(500, -500, nil) //t.Logf("%v", nodes) checkOrder(t, nodes, []string{"c", "g", "f", "e", "a", "h", "d"}) nodes = sortedset.GetRangeByScore(600, 500, nil) checkOrder(t, nodes, []string{}) nodes = sortedset.GetRangeByScore(500, 600, nil) checkOrder(t, nodes, []string{}) rank := sortedset.FindRank("f") if rank != 5 { t.Error("FindRank() does not return expected value `5`") } rank = sortedset.FindRank("d") if rank != 1 { t.Error("FindRank() does not return expected value `1`") } nodes = sortedset.GetRangeByScore(99, 100, nil) checkOrder(t, nodes, []string{"e", "f", "g", "c"}) nodes = sortedset.GetRangeByScore(90, 50, nil) checkOrder(t, nodes, []string{"a", "h"}) nodes = sortedset.GetRangeByScore(99, 100, &GetRangeByScoreOptions{ ExcludeStart: true, }) checkOrder(t, nodes, []string{"c"}) nodes = sortedset.GetRangeByScore(100, 99, &GetRangeByScoreOptions{ ExcludeStart: true, }) checkOrder(t, nodes, []string{"g", "f", "e"}) nodes = sortedset.GetRangeByScore(99, 100, &GetRangeByScoreOptions{ ExcludeEnd: true, }) checkOrder(t, nodes, []string{"e", "f", "g"}) nodes = sortedset.GetRangeByScore(100, 99, &GetRangeByScoreOptions{ ExcludeEnd: true, }) checkOrder(t, nodes, []string{"c"}) nodes = sortedset.GetRangeByScore(50, 100, &GetRangeByScoreOptions{ Limit: 2, }) checkOrder(t, nodes, []string{"h", "a"}) nodes = sortedset.GetRangeByScore(100, 50, &GetRangeByScoreOptions{ Limit: 2, }) checkOrder(t, nodes, []string{"c", "g"}) minNode := sortedset.PeekMin() if minNode == nil || minNode.Key() != "d" { t.Error("PeekMin() does not return expected value `d`") } minNode = sortedset.PopMin() if minNode == nil || minNode.Key() != "d" { t.Error("PopMin() does not return expected value `d`") } nodes = sortedset.GetRangeByScore(-500, 500, nil) checkOrder(t, nodes, []string{"h", "a", "e", "f", "g", "c"}) maxNode := sortedset.PeekMax() if maxNode == nil || maxNode.Key() != "c" { t.Error("PeekMax() does not return expected value `c`") } maxNode = sortedset.PopMax() if maxNode == nil || maxNode.Key() != "c" { t.Error("PopMax() does not return expected value `c`") } nodes = sortedset.GetRangeByScore(500, -500, nil) checkOrder(t, nodes, []string{"g", "f", "e", "a", "h"}) }