129 lines
4.9 KiB
Go
129 lines
4.9 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/article"
|
|
"encoding/json"
|
|
"net/http"
|
|
"testing"
|
|
)
|
|
|
|
func editorialField[T any](t *testing.T, response storyResponse, key string) T {
|
|
t.Helper()
|
|
var value T
|
|
if err := json.Unmarshal(response.fields(t)[key], &value); err != nil {
|
|
t.Fatalf("%s: %v in %s", key, err, response.text())
|
|
}
|
|
return value
|
|
}
|
|
|
|
func translationEntry(t *testing.T, response storyResponse, id string) map[string]json.RawMessage {
|
|
t.Helper()
|
|
for _, entry := range translationsOf(t, response) {
|
|
if string(entry["id"]) == id {
|
|
return entry
|
|
}
|
|
}
|
|
t.Fatalf("no translation %s in %s", id, response.text())
|
|
return nil
|
|
}
|
|
|
|
func putTrackingDraft(w *storyWorld) {
|
|
source := uint32(12)
|
|
w.put(article.Article{ID: 14, Title: "Costes", CreatedBy: storyRestrict, Slug: "costes", Lang: "es", StoryID: storyStory, SourceArticleID: &source, SourceRevision: 2})
|
|
}
|
|
|
|
func TestArticleEditorialContextHTTP(t *testing.T) {
|
|
t.Run("Missing languages are the enabled languages without a readable version", func(t *testing.T) {
|
|
w := newStoryWorld(t)
|
|
|
|
cases := []struct {
|
|
userID uint32
|
|
missing []string
|
|
}{
|
|
{storyOwner, []string{}},
|
|
{storyRestrict, []string{"de", "fr"}},
|
|
{storyReader, []string{}},
|
|
}
|
|
for _, c := range cases {
|
|
got := editorialField[[]string](t, w.send(c.userID, http.MethodGet, "/v1/article/10", ""), "missing_langs")
|
|
if len(got) != len(c.missing) || len(got) > 0 && (got[0] != c.missing[0] || got[1] != c.missing[1]) {
|
|
t.Errorf("user %d: missing_langs %v, want %v", c.userID, got, c.missing)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("A version in a disabled language or without language is left out of public surfaces", func(t *testing.T) {
|
|
w := newStoryWorld(t)
|
|
putTrackingDraft(w)
|
|
w.put(article.Article{ID: 30, Title: "Unassigned", CreatedBy: storyWriter1, Slug: "unassigned", StoryID: 30, IsOnline: true})
|
|
|
|
owner := w.send(storyOwner, http.MethodGet, "/v1/article/14", "")
|
|
if !editorialField[bool](t, owner, "excluded_from_public") || string(translationEntry(t, owner, "14")["excluded_from_public"]) != "true" || string(translationEntry(t, owner, "10")["excluded_from_public"]) != "false" {
|
|
t.Errorf("es must be left out, en kept: %s", owner.text())
|
|
}
|
|
if !editorialField[bool](t, w.send(storyOwner, http.MethodGet, "/v1/article/30", ""), "excluded_from_public") {
|
|
t.Error("a version without language must be left out of the public language surfaces")
|
|
}
|
|
if editorialField[bool](t, w.send(storyOwner, http.MethodGet, "/v1/article/10", ""), "excluded_from_public") {
|
|
t.Error("an enabled language must not be left out")
|
|
}
|
|
})
|
|
|
|
t.Run("A deleted source and an unreadable source read the same", func(t *testing.T) {
|
|
w := newStoryWorld(t)
|
|
putTrackingDraft(w)
|
|
|
|
tracked := w.send(storyOwner, http.MethodGet, "/v1/article/14", "")
|
|
unreadable := w.send(storyRestrict, http.MethodGet, "/v1/article/14", "")
|
|
delete(w.articles.articles, 12)
|
|
deleted := w.send(storyOwner, http.MethodGet, "/v1/article/14", "")
|
|
|
|
if string(tracked.fields(t)["source"]) != `{"article_id":12,"revision":2}` || editorialField[bool](t, tracked, "source_unavailable") {
|
|
t.Fatalf("a readable source is shown: %s", tracked.text())
|
|
}
|
|
for name, response := range map[string]storyResponse{"unreadable": unreadable, "deleted": deleted} {
|
|
if string(response.fields(t)["source"]) != "null" || !editorialField[bool](t, response, "source_unavailable") {
|
|
t.Errorf("%s source: %s", name, response.text())
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Translations name the source they track only when it is readable", func(t *testing.T) {
|
|
w := newStoryWorld(t)
|
|
putTrackingDraft(w)
|
|
|
|
owner := w.send(storyOwner, http.MethodGet, "/v1/article/10", "")
|
|
restricted := w.send(storyRestrict, http.MethodGet, "/v1/article/14", "")
|
|
|
|
if string(translationEntry(t, owner, "14")["source_article_id"]) != "12" || string(translationEntry(t, owner, "10")["source_article_id"]) != "null" {
|
|
t.Errorf("owner translations: %s", owner.text())
|
|
}
|
|
if string(translationEntry(t, restricted, "14")["source_article_id"]) != "null" {
|
|
t.Errorf("an unreadable source is named: %s", restricted.text())
|
|
}
|
|
})
|
|
|
|
t.Run("Partial view follows the read scope of the caller only", func(t *testing.T) {
|
|
w := newStoryWorld(t)
|
|
|
|
if editorialField[bool](t, w.send(storyOwner, http.MethodGet, "/v1/article/10", ""), "partial_view") {
|
|
t.Error("a caller who reads every version has a complete view")
|
|
}
|
|
if !editorialField[bool](t, w.send(storyRestrict, http.MethodGet, "/v1/article/13", ""), "partial_view") {
|
|
t.Error("a caller limited to own versions has a partial view")
|
|
}
|
|
})
|
|
|
|
t.Run("Anonymous reads carry no editorial keys", func(t *testing.T) {
|
|
w := newStoryWorld(t)
|
|
|
|
fields := w.send(storyAnon, http.MethodGet, "/v1/article/10", "").fields(t)
|
|
|
|
for _, key := range []string{"missing_langs", "excluded_from_public", "source_unavailable", "partial_view"} {
|
|
if _, present := fields[key]; present {
|
|
t.Errorf("anonymous read carries %s", key)
|
|
}
|
|
}
|
|
})
|
|
}
|