package services_test import ( "context" "encoding/json" "testing" "github.com/andyleap/hnh-map/internal/app" "github.com/andyleap/hnh-map/internal/app/services" "github.com/andyleap/hnh-map/internal/app/store" "go.etcd.io/bbolt" ) func TestFixMultipartContentType_NeedsQuoting(t *testing.T) { ct := "multipart/form-data; boundary=----WebKitFormBoundary=abc123" got := services.FixMultipartContentType(ct) want := `multipart/form-data; boundary="----WebKitFormBoundary=abc123"` if got != want { t.Fatalf("expected %q, got %q", want, got) } } func TestFixMultipartContentType_AlreadyQuoted(t *testing.T) { ct := `multipart/form-data; boundary="----WebKitFormBoundary"` got := services.FixMultipartContentType(ct) if got != ct { t.Fatalf("expected unchanged, got %q", got) } } func TestFixMultipartContentType_Normal(t *testing.T) { ct := "multipart/form-data; boundary=----WebKitFormBoundary" got := services.FixMultipartContentType(ct) if got != ct { t.Fatalf("expected unchanged, got %q", got) } } func newTestClientService(t *testing.T) (*services.ClientService, *store.Store) { t.Helper() db := newTestDB(t) st := store.New(db) mapSvc := services.NewMapService(services.MapServiceDeps{ Store: st, GridStorage: t.TempDir(), GridUpdates: &app.Topic[app.TileData]{}, }) client := services.NewClientService(services.ClientServiceDeps{ Store: st, MapSvc: mapSvc, WithChars: func(fn func(chars map[string]app.Character)) { fn(map[string]app.Character{}) }, }) return client, st } func TestClientLocate_Found(t *testing.T) { client, st := newTestClientService(t) ctx := context.Background() gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 2, Y: 3}} raw, _ := json.Marshal(gd) if err := st.Update(ctx, func(tx *bbolt.Tx) error { return st.PutGrid(tx, "g1", raw) }); err != nil { t.Fatal(err) } result, err := client.Locate(ctx, "g1") if err != nil { t.Fatal(err) } if result != "1;2;3" { t.Fatalf("expected 1;2;3, got %q", result) } } func TestClientLocate_NotFound(t *testing.T) { client, _ := newTestClientService(t) _, err := client.Locate(context.Background(), "ghost") if err == nil { t.Fatal("expected error for unknown grid") } } func TestClientProcessGridUpdate_EmptyGrids(t *testing.T) { client, _ := newTestClientService(t) ctx := context.Background() result, err := client.ProcessGridUpdate(ctx, services.GridUpdate{Grids: [][]string{}}) if err != nil { t.Fatal(err) } if result == nil { t.Fatal("expected non-nil result") } } func TestUploadMarkers_NormalizesCaveImage(t *testing.T) { client, st := newTestClientService(t) ctx := context.Background() body := []byte(`[{"Name":"Cave","GridID":"g1","X":10,"Y":20,"Image":"gfx/terobjs/mm/custom"}]`) if err := client.UploadMarkers(ctx, body); err != nil { t.Fatal(err) } var stored app.Marker if err := st.View(ctx, func(tx *bbolt.Tx) error { grid := st.GetMarkersGridBucket(tx) if grid == nil { t.Fatal("markers grid bucket not found") return nil } v := grid.Get([]byte("g1_10_20")) if v == nil { t.Fatal("marker g1_10_20 not found") return nil } return json.Unmarshal(v, &stored) }); err != nil { t.Fatal(err) } if stored.Image != "gfx/terobjs/mm/cave" { t.Fatalf("expected stored marker Image gfx/terobjs/mm/cave, got %q", stored.Image) } }