feat: Authors feature backend (and upgraded deprecated mods)
This commit is contained in:
1 parent
a11338094e
commit
b34a173d83
103 files changed
+6454
-240
No files matched your search
@@ -0,0 +1,122 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/author"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type recordingAuthorRepo struct {
|
||||
*mockAuthorRepo
|
||||
created []author.Author
|
||||
}
|
||||
|
||||
func (r *recordingAuthorRepo) Create(a author.Author) (author.Author, error) {
|
||||
a.ID = uint32(len(r.created) + 100)
|
||||
r.created = append(r.created, a)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func TestAuthorUseCaseGuards(t *testing.T) {
|
||||
t.Run("A taken slug is rejected by the use case itself", func(t *testing.T) {
|
||||
authors := &recordingAuthorRepo{mockAuthorRepo: plainAuthors()}
|
||||
authors.seed(1, "A", "taken")
|
||||
uc := useCases.NewCreateAuthorUseCase(authors, newMockUserRepo(), newMockImageRepo(), discardRecorder)
|
||||
|
||||
_, err := uc.Create(context.Background(), useCases.CreateAuthorCommand{Name: "B", Slug: "taken"})
|
||||
|
||||
if !errors.Is(err, author.ErrSlugTaken) || len(authors.created) != 0 {
|
||||
t.Errorf("err %v created %d", err, len(authors.created))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("The linked flag follows the user id on creation", func(t *testing.T) {
|
||||
users := newMockUserRepo()
|
||||
users.users[7] = userNamed(7, "u7", "U Seven")
|
||||
authors := &recordingAuthorRepo{mockAuthorRepo: plainAuthors()}
|
||||
uc := useCases.NewCreateAuthorUseCase(authors, users, newMockImageRepo(), discardRecorder)
|
||||
userID := uint32(7)
|
||||
|
||||
_, linkedErr := uc.Create(context.Background(), useCases.CreateAuthorCommand{Name: "Linked", UserID: &userID})
|
||||
_, freeErr := uc.Create(context.Background(), useCases.CreateAuthorCommand{Name: "Free"})
|
||||
|
||||
if linkedErr != nil || freeErr != nil || len(authors.created) != 2 {
|
||||
t.Fatalf("errs %v %v created %d", linkedErr, freeErr, len(authors.created))
|
||||
}
|
||||
if !authors.created[0].IsLinked || authors.created[1].IsLinked {
|
||||
t.Errorf("flags %v %v", authors.created[0].IsLinked, authors.created[1].IsLinked)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("The own author can use the fiftieth slug candidate", func(t *testing.T) {
|
||||
users := newMockUserRepo()
|
||||
users.users[1] = userNamed(1, "marta", "Marta Alves")
|
||||
authors := plainAuthors()
|
||||
base := author.GenerateSlug("Marta Alves")
|
||||
for attempt := 1; attempt < 50; attempt++ {
|
||||
authors.seed(uint32(attempt), "X", author.SlugWithSuffix(base, attempt))
|
||||
}
|
||||
uc := useCases.NewCreateMyAuthorUseCase(authors, users, discardRecorder)
|
||||
|
||||
created, err := uc.Create(context.Background(), 1)
|
||||
|
||||
if err != nil || created.Slug != author.SlugWithSuffix(base, 50) {
|
||||
t.Errorf("created %+v %v", created, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type staleCountAuthorRepo struct {
|
||||
*mockAuthorRepo
|
||||
}
|
||||
|
||||
func (s *staleCountAuthorRepo) Get(id uint32) (author.Author, error) {
|
||||
found, err := s.mockAuthorRepo.Get(id)
|
||||
found.ArticleCount = 0
|
||||
return found, err
|
||||
}
|
||||
|
||||
func TestAuthorDeleteRace(t *testing.T) {
|
||||
t.Run("A credit added after the count was read blocks the delete", func(t *testing.T) {
|
||||
base := plainAuthors()
|
||||
base.seed(2, "B", "b")
|
||||
base.articles.credits[10] = []uint32{2}
|
||||
uc := useCases.NewDeleteAuthorUseCase(&staleCountAuthorRepo{base}, discardRecorder)
|
||||
|
||||
err := uc.Delete(context.Background(), 2, useCases.Reassignment{Mode: useCases.ReassignAbsent})
|
||||
|
||||
if !errors.Is(err, author.ErrAuthorHasArticles) {
|
||||
t.Errorf("err = %v", err)
|
||||
}
|
||||
if _, exists := base.authors[2]; !exists {
|
||||
t.Errorf("author deleted despite credits")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Explicit removal uncredits the author", func(t *testing.T) {
|
||||
base := plainAuthors()
|
||||
base.seed(2, "B", "b")
|
||||
base.articles.credits[10] = []uint32{2, 3}
|
||||
uc := useCases.NewDeleteAuthorUseCase(base, discardRecorder)
|
||||
|
||||
err := uc.Delete(context.Background(), 2, useCases.Reassignment{Mode: useCases.ReassignNone})
|
||||
|
||||
if err != nil || len(base.articles.credits[10]) != 1 {
|
||||
t.Errorf("err %v credits %v", err, base.articles.credits[10])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorSocialTypes(t *testing.T) {
|
||||
for _, valid := range []string{author.SocialX, author.SocialLinkedIn, author.SocialGitHub, author.SocialMastodon, author.SocialCustom} {
|
||||
if !author.IsValidSocialType(valid) || author.ValidateLinks([]author.SocialLink{{Type: valid, URL: "https://a.example/x"}}) != nil {
|
||||
t.Errorf("%s refused", valid)
|
||||
}
|
||||
}
|
||||
err := author.ValidateLinks([]author.SocialLink{{Type: "facebook", URL: "https://a.example/x"}})
|
||||
if author.IsValidSocialType("") || !errors.Is(err, author.ErrInvalidSocialType) {
|
||||
t.Errorf("err = %v", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user