124 lines
4.2 KiB
Go
124 lines
4.2 KiB
Go
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)
|
|
|
|
result, err := uc.Create(context.Background(), 1)
|
|
created := result.Author
|
|
|
|
if err != nil || created.Slug != author.SlugWithSuffix(base, 50) || !result.SlugAdjusted {
|
|
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)
|
|
}
|
|
}
|