Enhance API documentation and improve marker functionality
- Updated API documentation for clarity and consistency, including detailed descriptions of authentication and user account endpoints. - Added a new cave marker image to enhance visual representation in the frontend. - Implemented normalization for cave marker images during upload to ensure consistent storage format. - Expanded test coverage for client services, including new tests for marker uploads and image normalization.
This commit is contained in:
@@ -1,93 +1,121 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user