feat: add /setcalendar command, store tests, and improve error handling
All checks were successful
CI / build (push) Successful in 48s

- Add /setcalendar command for calendar type parity (Settings UI)
- Add 17 store tests covering all repository methods
- Add handler tests for formatDuration, fmtHHMM, fmtDDHHMM
- Add domain tests for BurnoutLevel.String, NavMonth, FormatSalary
- Fix silent error discarding in save* helpers (log write failures)
- Fix computeAndAwardXP error handling instead of discarding
- Wrap critical store.go SQL errors with fmt.Errorf context
- Update README commands table with /setcalendar
This commit is contained in:
2026-06-25 15:56:00 +03:30
parent d9e13cb51d
commit 7dbd9fda12
8 changed files with 816 additions and 22 deletions

View File

@@ -157,6 +157,70 @@ func TestSanitizeNote(t *testing.T) {
}
}
func TestBurnoutLevelString(t *testing.T) {
cases := []struct {
level BurnoutLevel
want string
}{
{BurnoutHealthy, "Healthy"},
{BurnoutMild, "Mild concern"},
{BurnoutModerate, "Moderate concern"},
{BurnoutHigh, "High concern"},
{BurnoutLevel(99), "Unknown"},
}
for _, c := range cases {
got := c.level.String()
if got != c.want {
t.Errorf("BurnoutLevel(%d).String() = %q, want %q", c.level, got, c.want)
}
}
}
func TestNavMonth(t *testing.T) {
tests := []struct {
y, m int
prevY, prevM int
nextY, nextM int
}{
{2026, 6, 2026, 5, 2026, 7},
{2026, 1, 2025, 12, 2026, 2},
{2026, 12, 2026, 11, 2027, 1},
{2024, 2, 2024, 1, 2024, 3},
}
for _, tc := range tests {
prevY, prevM, nextY, nextM := NavMonth(tc.y, tc.m)
if prevY != tc.prevY || prevM != tc.prevM {
t.Errorf("NavMonth(%d, %d) prev = (%d, %d), want (%d, %d)", tc.y, tc.m, prevY, prevM, tc.prevY, tc.prevM)
}
if nextY != tc.nextY || nextM != tc.nextM {
t.Errorf("NavMonth(%d, %d) next = (%d, %d), want (%d, %d)", tc.y, tc.m, nextY, nextM, tc.nextY, tc.nextM)
}
}
}
func TestFormatSalary(t *testing.T) {
tests := []struct {
est SalaryEstimate
currency string
want string
wantShort string
}{
{SalaryEstimate{GrossEarning: 1000.50}, "$ USD", "$1000.50 USD", "$1000.50"},
{SalaryEstimate{GrossEarning: 0}, "$ USD", "$0.00 USD", "$0.00"},
{SalaryEstimate{GrossEarning: 2500}, "T Toman", "T2500.00 Toman", "T2500.00"},
}
for _, tc := range tests {
got := tc.est.FormatSalary(tc.currency)
if got != tc.want {
t.Errorf("FormatSalary(%q) = %q, want %q", tc.currency, got, tc.want)
}
gotShort := tc.est.FormatSalaryShort(tc.currency)
if gotShort != tc.wantShort {
t.Errorf("FormatSalaryShort(%q) = %q, want %q", tc.currency, gotShort, tc.wantShort)
}
}
}
func TestSanitizeDisplayName(t *testing.T) {
if got := SanitizeDisplayName(" Alice "); got != "Alice" {
t.Errorf("SanitizeDisplayName trim: got %q", got)