package test import ( "RenewCMS/internal/domain/article" "RenewCMS/internal/domain/author" "errors" "strings" "testing" ) func TestArticleTitleLengthBounds(t *testing.T) { cases := []struct { runes int valid bool }{ {article.MinTitleRunes - 1, false}, {article.MinTitleRunes, true}, {article.MaxTitleRunes, true}, {article.MaxTitleRunes + 1, false}, } for _, c := range cases { err := article.ValidateTitle(strings.Repeat("é", c.runes)) if (err == nil) != c.valid || (err != nil && !errors.Is(err, article.ErrInvalidTitle)) { t.Errorf("%d runes: err = %v", c.runes, err) } } } func TestArticleDetailedErrorsMatchTheirSentinel(t *testing.T) { cases := []struct { err error sentinel error }{ {&article.RevisionConflictError{Current: 4}, article.ErrRevisionConflict}, {&article.LanguageExistsError{ArticleID: 9}, article.ErrLanguageExists}, {&article.LanguageNotEnabledError{Missing: []string{"de"}}, article.ErrLanguageNotEnabled}, {&article.SlugConflictError{ArticleIDs: []uint32{3}}, article.ErrSlugConflict}, } for _, c := range cases { if !errors.Is(c.err, c.sentinel) || c.err.Error() != c.sentinel.Error() { t.Errorf("%T does not match %v", c.err, c.sentinel) } if errors.Is(c.err, article.ErrArticleNotFound) { t.Errorf("%T matches an unrelated sentinel", c.err) } } } func TestArticleRevisionsMoveByOne(t *testing.T) { opened := article.Article{}.Opened() cases := []struct { impact article.Impact edit, content uint32 }{ {article.Impact{}, 1, 1}, {article.Impact{Edited: true}, 2, 1}, {article.Impact{Edited: true, Content: true}, 2, 2}, } for _, c := range cases { revised := opened.Revised(c.impact) if revised.EditRevision != c.edit || revised.ContentRevision != c.content { t.Errorf("%+v: edit %d content %d", c.impact, revised.EditRevision, revised.ContentRevision) } } } func TestArticleCopiedIntoKeepsAnAuthorList(t *testing.T) { source := article.Article{ID: 7, Body: "

Body

", ContentRevision: 3} copied := source.CopiedInto(article.Article{Lang: "fr"}) if copied.Authors == nil || len(copied.Authors) != 0 { t.Fatalf("authors = %#v", copied.Authors) } if *copied.SourceArticleID != 7 || copied.SourceRevision != 3 || copied.Body != "

Body

" { t.Fatalf("copied = %+v", copied) } credited := article.Article{Authors: []author.Byline{{}}}.CopiedInto(article.Article{}) if len(credited.Authors) != 1 { t.Fatalf("credited authors = %#v", credited.Authors) } } func TestArticleStoryFiltersPerLanguage(t *testing.T) { cases := []struct { filters article.StoryFilters want bool }{ {article.StoryFilters{Lang: "fr"}, true}, {article.StoryFilters{Lang: "fr", Missing: true}, false}, {article.StoryFilters{}, false}, } for _, c := range cases { if got := c.filters.PerLanguage(); got != c.want { t.Errorf("%+v: PerLanguage = %v", c.filters, got) } } } func TestArticleSEOSummaryStale(t *testing.T) { if !(article.SEOSummary{}).Stale() || (article.SEOSummary{Status: article.SEOStatusReady}).Stale() { t.Fatal("only a summary without status is stale") } }