diff --git a/internal/adif/import_e2e_test.go b/internal/adif/import_e2e_test.go new file mode 100644 index 0000000..e163dfc --- /dev/null +++ b/internal/adif/import_e2e_test.go @@ -0,0 +1,74 @@ +package adif_test + +import ( + "context" + "os" + "path/filepath" + "strings" + "testing" + + "hamlog/internal/adif" + "hamlog/internal/db" + "hamlog/internal/qso" +) + +// End to end: an operator's own record, through a real SQLite logbook and back. +// +// Written because CONTEST_ID was reported as "not imported". It is imported, and +// this pins the whole path — parse, remap, insert, read back — rather than the +// conversion step alone, which was already green while the report stood. A field +// can be lost at five places between the file and the grid; only the round trip +// says which. +func TestContestIDSurvivesImport(t *testing.T) { + dir := t.TempDir() + conn, err := db.Open(filepath.Join(dir, "logbook.db")) + if err != nil { + t.Fatalf("open: %v", err) + } + defer conn.Close() + + const file = "2E0CVN 20260725 120039 EU005 20M 14.014 CW RSGB-IOTA 599 599 001EU005 \n" + path := filepath.Join(dir, "in.adi") + if err := os.WriteFile(path, []byte(file), 0o644); err != nil { + t.Fatal(err) + } + + repo := qso.NewRepo(conn) + im := &adif.Importer{Repo: repo, FieldMap: map[string]string{"state": "iota"}} + res, err := im.ImportFile(context.Background(), path) + if err != nil { + t.Fatalf("import: %v", err) + } + t.Logf("result: %+v", res) + + rows, err := conn.Query("SELECT callsign, contest_id, iota, state FROM qso") + if err != nil { + t.Fatal(err) + } + defer rows.Close() + n := 0 + for rows.Next() { + var call, contest, iota, state any + if err := rows.Scan(&call, &contest, &iota, &state); err != nil { + t.Fatal(err) + } + n++ + t.Logf("stored: call=%v contest_id=%v iota=%v state=%v", call, contest, iota, state) + if s := strings.TrimSpace(toS(contest)); s != "RSGB-IOTA" { + t.Errorf("contest_id in the DATABASE = %q, want RSGB-IOTA", s) + } + } + if n == 0 { + t.Fatal("nothing was stored") + } +} + +func toS(v any) string { + switch x := v.(type) { + case string: + return x + case []byte: + return string(x) + } + return "" +}