package console import ( "encoding/json" "fmt" "strings" "testing" "time" ) // TestFaqContentDecode pins the Docker-free decoding of a Winter FAQ export // row: content as a JSON list, as JSON text, as an object keyed by row // number (in numeric order), or null; the required name, slug and locale // code; PHP-shaped flags, ids and timestamps; and the refusals. func TestFaqContentDecode(t *testing.T) { for _, tc := range []struct { raw string want string }{ {`[{"question":"Q1","answer":"

A1

"},{"question":"Q2","answer":null}]`, `[map[answer:

A1

question:Q1] map[answer: question:Q2]]`}, {`"[{\"question\":\"Q\",\"answer\":\"A\"}]"`, `[map[answer:A question:Q]]`}, {`{"10":{"question":"ten"},"2":{"question":"two"},"1":{"question":"one"}}`, `[map[question:one] map[question:two] map[question:ten]]`}, {`[]`, `[]`}, {`null`, `[]`}, {`"null"`, `[]`}, {``, `[]`}, } { got, err := decodeContent(json.RawMessage(tc.raw)) if err != nil { t.Fatalf("decodeContent(%s): %v", tc.raw, err) } if s := fmt.Sprint(got); s != tc.want { t.Fatalf("decodeContent(%s) = %s, want %s", tc.raw, s, tc.want) } } for _, raw := range []string{`"x"`, `5`, `[1,2]`, `{"a":1}`, `true`} { if _, err := decodeContent(json.RawMessage(raw)); err == nil { t.Fatalf("decodeContent(%s) accepted", raw) } } row := func(raw string) map[string]json.RawMessage { t.Helper() var out map[string]json.RawMessage if err := json.Unmarshal([]byte(raw), &out); err != nil { t.Fatal(err) } return out } faq, code, err := decodeFAQ(row(`{"id": "12", "name": "Shipping", "slug": "shipping", "locale_code": "pl", "is_active": "1", "description": 5, "content": [{"question":"Q","answer":"A"}], "created_at": "2024-03-01 10:00:00.000000", "updated_at": null}`)) if err != nil { t.Fatal(err) } if faq.ID != 12 || faq.Name != "Shipping" || faq.Slug != "shipping" || code != "pl" || !faq.IsActive || faq.Description == nil || *faq.Description != "5" || len(faq.Items()) != 1 || !faq.Content.Valid || faq.CreatedAt == nil || !faq.CreatedAt.Equal(time.Date(2024, 3, 1, 10, 0, 0, 0, time.UTC)) || faq.UpdatedAt != nil { t.Fatalf("decoded = %+v code=%s", faq, code) } if faq, _, err := decodeFAQ(row(`{"id": 1, "name": "A", "slug": "a", "locale_code": "en", "is_active": 0, "content": null}`)); err != nil || faq.IsActive || faq.Content.Valid || faq.Description != nil { t.Fatalf("null content row = %+v %v", faq, err) } for raw, want := range map[string]string{ `{"id": 0, "name": "A", "slug": "a", "locale_code": "en"}`: "id", `{"name": "A", "slug": "a", "locale_code": "en"}`: "id", `{"id": 1, "slug": "a", "locale_code": "en"}`: "name is missing", `{"id": 1, "name": "A", "slug": " ", "locale_code": "en"}`: "slug is missing", `{"id": 1, "name": "A", "slug": "a"}`: "locale_code is missing", `{"id": 1, "name": "A", "slug": "a", "locale_code": "en", "content": "oops"}`: "content", `{"id": 1, "name": "A", "slug": "a", "locale_code": "en", "is_active": [1]}`: "is_active", `{"id": 1, "name": "A", "slug": "a", "locale_code": "en", "created_at": "x"}`: "created_at", `{"id": 1, "name": "A", "slug": "a", "locale_code": "en", "description": {}}`: "description", } { if _, _, err := decodeFAQ(row(raw)); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("decodeFAQ(%s) = %v, want %q", raw, err, want) } } }