package api
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"craftdesign.group/quarry/internal/ops"
)
// A coded refusal reaches a JSON client as a 400 whose body carries the
// code and fields beside the sentence, so a client can act on it
// without parsing prose.
func TestACodedRefusalCarriesItsCodeAndFieldsInTheBody(t *testing.T) {
err := fmt.Errorf("accepting: %w", &ops.Refusal{
Code: RefusalBranchMoved, Message: "moved",
Fields: map[string]string{"expected": "aaa", "current": "bbb"}})
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/api/v1/r/x/landing/y/accept", nil)
writeOpError(w, req, "landing.accept", err)
if w.Code != http.StatusBadRequest {
t.Fatalf("FAIL: status %d, want 400", w.Code)
}
var body map[string]string
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
t.Fatal(err)
}
for k, want := range map[string]string{"code": "branch_moved", "expected": "aaa", "current": "bbb"} {
if body[k] != want {
t.Errorf("FAIL: body[%q] = %q, want %q (body %v)", k, body[k], want, body)
}
}
if body["error"] == "" {
t.Errorf("FAIL: body has no error sentence: %v", body)
}
}
// A plain refusal keeps the one-key body every client already reads.
func TestAnUncodedRefusalKeepsTheOneKeyBody(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/", nil)
writeOpError(w, req, "x", fmt.Errorf("no: %w", ops.ErrInvalid))
var body map[string]string
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
t.Fatal(err)
}
if len(body) != 1 || body["error"] == "" {
t.Fatalf("FAIL: body %v; want only error", body)
}
}