package main import ( "testing" "time" "hamlog/internal/qso" ) func at(s string) time.Time { t, err := time.Parse("2006-01-02 15:04", s) if err != nil { panic(err) } return t } // The number is the contact's rank in the WHOLE log, not its position in what // the grid happens to be showing. Ranking inside the result would renumber // every contact the moment a filter is applied, and QSO #1 would change // identity as the operator typed. func TestQSONumberIsGlobalNotPerPage(t *testing.T) { a := &App{} // The log, oldest first: ids are deliberately NOT in date order, which is // exactly what an imported ADIF produces. a.qsoNumbers = map[int64]int{ 770: 1, // oldest, imported last so it has the highest id 101: 2, 102: 3, 103: 4, } // A filtered page holding only two of them, newest first as the grid asks. page := []qso.QSO{{ID: 103}, {ID: 770}} a.stampQSONumbers(page) if page[0].Number != 4 { t.Errorf("id 103 numbered %d, want 4", page[0].Number) } if page[1].Number != 1 { t.Errorf("id 770 numbered %d, want 1 — the oldest contact, whatever its id", page[1].Number) } } // A contact logged now is the newest, so it takes the next number without // rereading the log — a full scan per QSO would be felt in a contest run. func TestNewQSOTakesTheNextNumber(t *testing.T) { a := &App{} a.qsoNumbers = map[int64]int{1: 1, 2: 2, 3: 3} a.qsoNumMax = at("2026-08-13 10:00") a.noteQSONumbered(9, at("2026-08-13 11:00")) if got := a.qsoNumbers[9]; got != 4 { t.Errorf("new QSO numbered %d, want 4", got) } if !a.qsoNumMax.Equal(at("2026-08-13 11:00")) { t.Error("the newest date was not carried forward") } } // A contact entered with an OLDER date belongs in the middle of the order. // Appending it would number it last, which is wrong — so the map is dropped and // rebuilt correctly instead. func TestBackdatedQSOForcesARebuild(t *testing.T) { a := &App{} a.qsoNumbers = map[int64]int{1: 1, 2: 2, 3: 3} a.qsoNumMax = at("2026-08-13 10:00") a.noteQSONumbered(9, at("2020-01-01 09:00")) if a.qsoNumbers != nil { t.Errorf("a back-dated QSO was appended as the newest: %v", a.qsoNumbers) } } // Nothing built yet: the lazy build will see the new contact anyway, so this // must not create a one-entry map that then numbers the whole log wrongly. func TestNoteBeforeAnyBuildDoesNothing(t *testing.T) { a := &App{} a.noteQSONumbered(9, at("2026-08-13 11:00")) if a.qsoNumbers != nil { t.Errorf("built a map from a single contact: %v", a.qsoNumbers) } } // With no index available the column is simply empty — never wrong. func TestStampWithoutIndexLeavesZero(t *testing.T) { a := &App{} // no qso repo, so the index cannot be built page := []qso.QSO{{ID: 1}, {ID: 2}} a.stampQSONumbers(page) for _, q := range page { if q.Number != 0 { t.Errorf("invented a number without an index: %d", q.Number) } } }