71 lines
2.9 KiB
Go
71 lines
2.9 KiB
Go
package udp
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
const ms = 1000
|
|
|
|
func sec(h, m, s int) uint32 { return uint32((h*3600 + m*60 + s) * ms) }
|
|
|
|
// WSJT-X stamps a decode with a time of DAY and no date, so the date has to come
|
|
// from our own clock — and around midnight the two disagree. A decode stamped
|
|
// 23:59:58 that reaches us at 00:00:01 would be dated the NEW day, putting it
|
|
// almost 24 hours in the future: it would sort to the top of the decodes panel
|
|
// and stay there for the rest of the session, and its period would never line up
|
|
// with the ones around it.
|
|
//
|
|
// The clock is passed IN. The previous version of this test read the real one
|
|
// and so failed every afternoon — a 23:59:58 stamp seen at 17:00 is genuinely
|
|
// hours in the future, and no rule can make it otherwise. A suite that is red
|
|
// for half the day is a suite nobody reads.
|
|
func TestDecodeTimeCrossesMidnight(t *testing.T) {
|
|
// Just after midnight, a stamp from the last seconds of yesterday.
|
|
now := time.Date(2026, 3, 14, 0, 0, 1, 0, time.UTC)
|
|
got := decodeTimeAt(sec(23, 59, 58), now)
|
|
if want := time.Date(2026, 3, 13, 23, 59, 58, 0, time.UTC); !got.Equal(want) {
|
|
t.Errorf("23:59:58 seen at 00:00:01 → %s, want %s (yesterday)", got, want)
|
|
}
|
|
if got.After(now) {
|
|
t.Errorf("%s is in the future — it would sort to the top of the list for the session", got)
|
|
}
|
|
}
|
|
|
|
// The mirror case: just before midnight, a stamp from the first seconds of
|
|
// tomorrow. Our clock is still on the old day.
|
|
func TestDecodeTimeCrossesMidnightBackwards(t *testing.T) {
|
|
now := time.Date(2026, 3, 13, 23, 59, 58, 0, time.UTC)
|
|
got := decodeTimeAt(sec(0, 0, 1), now)
|
|
if want := time.Date(2026, 3, 14, 0, 0, 1, 0, time.UTC); !got.Equal(want) {
|
|
t.Errorf("00:00:01 seen at 23:59:58 → %s, want %s (tomorrow)", got, want)
|
|
}
|
|
}
|
|
|
|
// The ordinary case, which is every decode that is not within a few seconds of
|
|
// midnight: the stamp belongs to today and is left alone.
|
|
func TestDecodeTimeOrdinary(t *testing.T) {
|
|
now := time.Date(2026, 3, 13, 14, 30, 0, 0, time.UTC)
|
|
got := decodeTimeAt(sec(14, 29, 45), now)
|
|
if want := time.Date(2026, 3, 13, 14, 29, 45, 0, time.UTC); !got.Equal(want) {
|
|
t.Errorf("a stamp close to now → %s, want %s", got, want)
|
|
}
|
|
}
|
|
|
|
// The whole point of the timestamp is grouping, so two decodes from the same
|
|
// fifteen-second slot must floor to the same period however far apart in the
|
|
// slot they were heard.
|
|
func TestDecodesInOneSlotShareAPeriod(t *testing.T) {
|
|
now := time.Date(2026, 3, 13, 12, 30, 7, 0, time.UTC)
|
|
at := func(h, m, s int) time.Time { return decodeTimeAt(sec(h, m, s), now) }
|
|
floor := func(x time.Time) int64 { return x.Unix() / 15 * 15 }
|
|
|
|
a, b := at(12, 30, 0), at(12, 30, 14)
|
|
if floor(a) != floor(b) {
|
|
t.Errorf("%s and %s fell in different periods", a, b)
|
|
}
|
|
if floor(at(12, 30, 14)) == floor(at(12, 30, 15)) {
|
|
t.Error("12:30:14 and 12:30:15 are different slots and must not share a period")
|
|
}
|
|
}
|