package api
import (
"encoding/json"
"net/http/httptest"
"strings"
"testing"
"time"
)
func TestDecodePostRules(t *testing.T) {
cases := []struct {
name string
body string
wantCode int
wantText string
}{
{"published news", `{"title":"День открытых дверей","html":"
Текст
","published_at":"2026-09-17","published":true}`, 200, ""},
{"draft without text", `{"title":"Черновик","published":false}`, 200, ""},
{"picture-only post", `{"title":"Афиша","html":"
","published":true}`, 200, ""},
{"no title", `{"title":" ","published":false}`, 422, "заголовок"},
{"published without text", `{"title":"Пусто","html":"
","published":true}`, 422, "добавьте текст"},
{"bad date", `{"title":"Дата","published_at":"17.09.2026"}`, 422, "ГГГГ-ММ-ДД"},
{"bad slug", `{"title":"Адрес","slug":"новость"}`, 422, "латинские"},
// адреса со старого сайта: хвостовой дефис, подчёркивание — запись должна сохраняться
{"legacy slug", `{"title":"Старая","slug":"v-klinike-dana-","published":false}`, 200, ""},
{"legacy underscore", `{"title":"Старая","slug":"lech_bol","published":false}`, 200, ""},
{"leading dash", `{"title":"Адрес","slug":"-dana"}`, 422, "латинские"},
}
for _, tc := range cases {
w := httptest.NewRecorder()
r := httptest.NewRequest("POST", "/api/v1/admin/news", strings.NewReader(tc.body))
_, valid := decodePost(w, r, "news")
code := 200
if !valid {
code = w.Code
}
if code != tc.wantCode || (tc.wantText != "" && !strings.Contains(w.Body.String(), tc.wantText)) {
t.Errorf("%s: got %d %s, want %d containing %q", tc.name, code, w.Body.String(), tc.wantCode, tc.wantText)
}
}
}
func TestDecodePostStoresHTMLBlockAndDate(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest("POST", "/", strings.NewReader(`{"title":"Статья","html":"Раздел
","published_at":"2025-05-28"}`))
in, valid := decodePost(w, r, "article")
if !valid {
t.Fatal(w.Body.String())
}
var blocks []map[string]string
if err := json.Unmarshal(in.Blocks, &blocks); err != nil || len(blocks) != 1 || blocks[0]["html"] != "Раздел
" {
t.Errorf("blocks = %s", in.Blocks)
}
if in.Slug != "statya" {
t.Errorf("slug = %s", in.Slug)
}
if got := in.PublishedAt.UTC().Format(time.RFC3339); got != "2025-05-28T09:00:00Z" {
t.Errorf("published_at = %s, want midday Moscow", got)
}
// неизменённая дата возвращается полной меткой времени и сохраняется как есть
w = httptest.NewRecorder()
r = httptest.NewRequest("POST", "/", strings.NewReader(`{"title":"Статья","published_at":"2024-01-13T14:03:41+03:00"}`))
in, _ = decodePost(w, r, "article")
if got := in.PublishedAt.UTC().Format(time.RFC3339); got != "2024-01-13T11:03:41Z" {
t.Errorf("kept published_at = %s", got)
}
}
func TestDecodeVacancy(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest("POST", "/", strings.NewReader(`{"title":"Администратор","requirements":"- грамотная речь\r\n\r\n• ответственность ","published":true}`))
in, valid := decodeVacancy(w, r)
if !valid {
t.Fatal(w.Body.String())
}
if in.Requirements != "грамотная речь\nответственность" || in.Slug != "administrator" || in.Sort != 100 {
t.Errorf("got %+v", in)
}
w = httptest.NewRecorder()
r = httptest.NewRequest("POST", "/", strings.NewReader(`{"title":"Пустая","published":true}`))
if _, valid := decodeVacancy(w, r); valid || !strings.Contains(w.Body.String(), "опишите") {
t.Errorf("empty published vacancy accepted: %d %s", w.Code, w.Body.String())
}
}