1package tally23import (4 "testing"56 "gno.land/p/nt/uassert/v0"7)89func keys(entries []Entry) string {10 out := ""11 for i, e := range entries {12 if i > 0 {13 out += ","14 }15 out += e.Key16 }17 return out18}1920func TestSortOrdersByScoreThenKey(t *testing.T) {21 cases := []struct {22 name string23 in []Entry24 want string25 }{26 {"already ordered", []Entry{{"a", 3}, {"b", 2}, {"c", 1}}, "a,b,c"},27 {"reversed", []Entry{{"c", 1}, {"b", 2}, {"a", 3}}, "a,b,c"},28 {"all tied, key decides", []Entry{{"c", 5}, {"a", 5}, {"b", 5}}, "a,b,c"},29 {"partial tie", []Entry{{"z", 1}, {"b", 9}, {"a", 9}}, "a,b,z"},30 {"negatives sort below", []Entry{{"a", -1}, {"b", 0}, {"c", 1}}, "c,b,a"},31 {"single", []Entry{{"only", 7}}, "only"},32 {"empty", nil, ""},33 }34 for _, tc := range cases {35 t.Run(tc.name, func(t *testing.T) {36 in := make([]Entry, len(tc.in))37 copy(in, tc.in)38 Sort(in)39 uassert.Equal(t, tc.want, keys(in))40 })41 }42}4344// TestSortIsATotalOrder is the defect this package exists to remove. A45// comparator whose last clause repeats the score (rpgroom's third clause) is46// not a total order: two equal rows compare false both ways and their order is47// decided by the algorithm. Sorting twice from different inputs must agree.48func TestSortIsATotalOrder(t *testing.T) {49 a := []Entry{{"x", 5}, {"y", 5}, {"z", 5}, {"w", 9}}50 b := []Entry{{"z", 5}, {"w", 9}, {"y", 5}, {"x", 5}}51 Sort(a)52 Sort(b)53 uassert.Equal(t, keys(a), keys(b))54 uassert.Equal(t, "w,x,y,z", keys(a))55}5657func TestTop(t *testing.T) {58 in := []Entry{{"c", 1}, {"a", 3}, {"b", 2}}59 uassert.Equal(t, "a,b", keys(Top(in, 2)))60 uassert.Equal(t, "a,b,c", keys(Top(in, 10)))61 uassert.Equal(t, "", keys(Top(in, 0)))62 uassert.Equal(t, "", keys(Top(in, -1)))63 uassert.Equal(t, "", keys(Top(nil, 3)))64}6566// TestTopDoesNotDisturbTheCaller pins that Top copies. A realm that renders a67// Top(3) and then iterates its own slice must not find it reordered.68func TestTopDoesNotDisturbTheCaller(t *testing.T) {69 in := []Entry{{"c", 1}, {"a", 3}, {"b", 2}}70 _ = Top(in, 2)71 uassert.Equal(t, "c,a,b", keys(in))72}7374func TestRank(t *testing.T) {75 in := []Entry{{"c", 1}, {"a", 3}, {"b", 2}}76 uassert.Equal(t, 1, Rank(in, "a"))77 uassert.Equal(t, 2, Rank(in, "b"))78 uassert.Equal(t, 3, Rank(in, "c"))79 uassert.Equal(t, 0, Rank(in, "absent"))80}8182// TestRankNeverTies is what makes a rendered "#3" mean something: two equal83// scores still get 2 and 3, never 2 and 2.84func TestRankNeverTies(t *testing.T) {85 in := []Entry{{"a", 5}, {"b", 5}, {"c", 5}}86 seen := map[int]bool{}87 for _, e := range in {88 r := Rank(in, e.Key)89 if seen[r] {90 t.Errorf("rank %d claimed twice", r)91 }92 seen[r] = true93 }94 uassert.Equal(t, 3, len(seen))95}9697func TestBoardAddAndScore(t *testing.T) {98 b := NewBoard()99 uassert.Equal(t, 0, b.Len())100 uassert.Equal(t, int64(5), b.Add("a", 5))101 uassert.Equal(t, int64(8), b.Add("a", 3))102 uassert.Equal(t, int64(6), b.Add("a", -2))103 uassert.Equal(t, int64(6), b.Score("a"))104 uassert.Equal(t, int64(0), b.Score("never"))105 uassert.Equal(t, 1, b.Len())106}107108func TestBoardHasDistinguishesAbsentFromZero(t *testing.T) {109 b := NewBoard()110 b.Set("zero", 0)111 uassert.True(t, b.Has("zero"))112 uassert.False(t, b.Has("absent"))113 uassert.Equal(t, int64(0), b.Score("zero"))114 uassert.Equal(t, int64(0), b.Score("absent"))115}116117func TestBoardRemove(t *testing.T) {118 b := NewBoard()119 b.Set("a", 1)120 uassert.True(t, b.Remove("a"))121 uassert.False(t, b.Remove("a"))122 uassert.Equal(t, 0, b.Len())123}124125func TestBoardEntriesAndTop(t *testing.T) {126 b := NewBoard()127 b.Set("c", 1)128 b.Set("a", 3)129 b.Set("b", 3)130 uassert.Equal(t, "a,b,c", keys(b.Entries()))131 uassert.Equal(t, "a,b", keys(b.Top(2)))132 uassert.Equal(t, 1, b.Rank("a"))133 uassert.Equal(t, 2, b.Rank("b"))134 uassert.Equal(t, 0, b.Rank("absent"))135}136137// TestBoardOrderDoesNotDependOnInsertion is the reason Board is backed by a138// tree and not a map: the same scores inserted in a different order must139// render identically.140func TestBoardOrderDoesNotDependOnInsertion(t *testing.T) {141 one := NewBoard()142 for _, e := range []Entry{{"a", 5}, {"b", 5}, {"c", 9}} {143 one.Set(e.Key, e.Score)144 }145 two := NewBoard()146 for _, e := range []Entry{{"c", 9}, {"b", 5}, {"a", 5}} {147 two.Set(e.Key, e.Score)148 }149 uassert.Equal(t, keys(one.Entries()), keys(two.Entries()))150 uassert.Equal(t, "c,a,b", keys(one.Entries()))151}152Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.