feat: implement 8 features across full stack
- Leaderboard: rank-based percentile tiers (champion/gold/silver/bronze),
deterministic tie-breaking (xp DESC, user_id ASC)
- Mentor chat: md: breakpoints, safe-area-inset-bottom padding
- Learning progress: server-side progressPct, curriculum expansion safety
- Physical orders: hard-disabled with 410 Gone
- Certificate approval: pending/issued flow, admin issue/revoke endpoints,
certificate_requires_approval setting (migration 0031)
- Draft/publish: is_published on lessons and chapters, admin publish UI
(migration 0030)
- Video panel: static thumbnails (no preload), client-side pagination
- Rich editor: TipTap + tiptap-markdown for lesson descriptions,
marked + DOMPurify for SafeMarkdown rendering
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package api
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTierFromRank(t *testing.T) {
|
||||
cases := []struct {
|
||||
rank, total int
|
||||
want string
|
||||
}{
|
||||
{1, 1, "champion"},
|
||||
{1, 100, "champion"},
|
||||
{1, 0, "bronze"}, // zero total → bronze (guard)
|
||||
{0, 100, "bronze"}, // zero rank → bronze (guard)
|
||||
{10, 100, "gold"}, // exactly 10%
|
||||
{11, 100, "silver"}, // 11%
|
||||
{30, 100, "silver"}, // exactly 30%
|
||||
{31, 100, "bronze"}, // 31%
|
||||
{5, 50, "gold"}, // 10%
|
||||
{15, 50, "silver"}, // exactly 30%
|
||||
{16, 50, "bronze"}, // 32% → bronze
|
||||
{50, 100, "bronze"},
|
||||
{2, 10, "silver"}, // 20% → silver
|
||||
{1, 10, "champion"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := tierFromRank(c.rank, c.total)
|
||||
if got != c.want {
|
||||
t.Errorf("tierFromRank(%d, %d) = %q; want %q", c.rank, c.total, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user