483 lines
18 KiB
Go
483 lines
18 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/article"
|
|
"RenewCMS/internal/domain/author"
|
|
"RenewCMS/internal/infrastructure/persistence/database"
|
|
entity "RenewCMS/internal/infrastructure/persistence/models"
|
|
persistence "RenewCMS/internal/infrastructure/persistence/repositories"
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func mustCreateAuthor(t *testing.T, authors *persistence.AuthorRepository, name string, slug string, userID *uint32) author.Author {
|
|
t.Helper()
|
|
created, err := authors.Create(author.Author{Name: name, Slug: slug, SocialLinks: []author.SocialLink{}, UserID: userID})
|
|
if err != nil {
|
|
t.Fatalf("create author %q: %v", slug, err)
|
|
}
|
|
return created
|
|
}
|
|
|
|
func mustCreateCreditedArticle(t *testing.T, db *gorm.DB, title string, authorIDs ...uint32) article.Article {
|
|
t.Helper()
|
|
bylines := make([]author.Byline, 0, len(authorIDs))
|
|
for _, id := range authorIDs {
|
|
bylines = append(bylines, author.Byline{ID: id})
|
|
}
|
|
created, err := persistence.NewArticleRepository(db).Create(article.Article{Title: title, Body: "Body", Authors: bylines})
|
|
if err != nil {
|
|
t.Fatalf("create article: %v", err)
|
|
}
|
|
return created
|
|
}
|
|
|
|
func creditedIDs(t *testing.T, db *gorm.DB, articleID uint32) []uint32 {
|
|
t.Helper()
|
|
found, err := persistence.NewArticleRepository(db).Get(articleID)
|
|
if err != nil {
|
|
t.Fatalf("get article: %v", err)
|
|
}
|
|
ids := []uint32{}
|
|
for _, byline := range found.Authors {
|
|
ids = append(ids, byline.ID)
|
|
}
|
|
return ids
|
|
}
|
|
|
|
func TestAuthorRepositoryContract(t *testing.T) {
|
|
backends := []contractBackend{
|
|
{name: "sqlite", open: openContractSQLite},
|
|
{name: "mysql", open: openContractMySQL},
|
|
{name: "postgres", open: openContractPostgres},
|
|
}
|
|
cases := []struct {
|
|
name string
|
|
run func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository)
|
|
}{
|
|
{"create and read back every field", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
website := "https://example.com"
|
|
created, err := authors.Create(author.Author{Name: "Camille", Slug: "camille", Bio: "Bio", Website: &website, SocialLinks: []author.SocialLink{{Type: "x", URL: "https://x.com/c"}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
found, err := authors.Get(created.ID)
|
|
|
|
if err != nil || found.Name != "Camille" || found.Bio != "Bio" || *found.Website != website || len(found.SocialLinks) != 1 || found.IsLinked || found.ArticleCount != 0 {
|
|
t.Errorf("found %+v %v", found, err)
|
|
}
|
|
bySlug, _ := authors.GetBySlug("camille")
|
|
if bySlug.ID != created.ID {
|
|
t.Errorf("by slug %+v", bySlug)
|
|
}
|
|
}},
|
|
{"a missing author is a domain error", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
if _, err := authors.Get(99); !errors.Is(err, author.ErrAuthorNotFound) {
|
|
t.Errorf("get: %v", err)
|
|
}
|
|
if _, err := authors.GetBySlug("nope"); !errors.Is(err, author.ErrAuthorNotFound) {
|
|
t.Errorf("slug: %v", err)
|
|
}
|
|
if _, err := authors.GetByUserID(9); !errors.Is(err, author.ErrAuthorNotFound) {
|
|
t.Errorf("user: %v", err)
|
|
}
|
|
if err := authors.DeleteMovingCredits(99, nil); !errors.Is(err, author.ErrAuthorNotFound) {
|
|
t.Errorf("delete: %v", err)
|
|
}
|
|
}},
|
|
{"slug and user are unique while many guests are allowed", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
user := uint32(1)
|
|
mustCreateAuthor(t, authors, "A", "a", &user)
|
|
mustCreateAuthor(t, authors, "B", "b", nil)
|
|
mustCreateAuthor(t, authors, "C", "c", nil)
|
|
|
|
_, slugErr := authors.Create(author.Author{Name: "D", Slug: "a", SocialLinks: []author.SocialLink{}})
|
|
_, userErr := authors.Create(author.Author{Name: "E", Slug: "e", SocialLinks: []author.SocialLink{}, UserID: &user})
|
|
|
|
if !errors.Is(slugErr, author.ErrSlugTaken) || !errors.Is(userErr, author.ErrUserAlreadyLinked) {
|
|
t.Errorf("slug %v user %v", slugErr, userErr)
|
|
}
|
|
b, _ := authors.GetBySlug("b")
|
|
b.Slug = "a"
|
|
if _, err := authors.Update(b); !errors.Is(err, author.ErrSlugTaken) {
|
|
t.Errorf("update: %v", err)
|
|
}
|
|
}},
|
|
{"update changes every field and can clear the nullable ones", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
user := uint32(4)
|
|
website := "https://example.com"
|
|
created := mustCreateAuthor(t, authors, "A", "a", &user)
|
|
created.Name = "Z"
|
|
created.Website = &website
|
|
created.UserID = nil
|
|
created.SocialLinks = []author.SocialLink{{Type: "custom", URL: "https://c.example"}}
|
|
|
|
updated, err := authors.Update(created)
|
|
|
|
if err != nil || updated.Name != "Z" || updated.UserID != nil || updated.IsLinked || *updated.Website != website || len(updated.SocialLinks) != 1 {
|
|
t.Errorf("updated %+v %v", updated, err)
|
|
}
|
|
updated.Website = nil
|
|
cleared, _ := authors.Update(updated)
|
|
if cleared.Website != nil {
|
|
t.Errorf("cleared %+v", cleared)
|
|
}
|
|
}},
|
|
{"the list is newest first, searchable and paginated", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
for i := 1; i <= 7; i++ {
|
|
mustCreateAuthor(t, authors, fmt.Sprintf("Writer %d", i), fmt.Sprintf("writer-%d", i), nil)
|
|
}
|
|
mustCreateAuthor(t, authors, "Inès Duarte", "zl", nil)
|
|
|
|
page, err := authors.List(author.ListQuery{Page: 2, Size: 5})
|
|
search, _ := authors.List(author.ListQuery{Q: "INES", Page: 1, Size: 25})
|
|
bySlug, _ := authors.List(author.ListQuery{Q: "zl", Page: 1, Size: 25})
|
|
none, _ := authors.List(author.ListQuery{Q: "nobody", Page: 1, Size: 25})
|
|
|
|
if err != nil || page.Total != 8 || len(page.Items) != 3 || page.Items[0].Name != "Writer 3" {
|
|
t.Errorf("page %+v %v", page, err)
|
|
}
|
|
if search.Total != 1 || bySlug.Total != 1 || none.Total != 0 || len(none.Items) != 0 {
|
|
t.Errorf("search %+v slug %+v none %+v", search, bySlug, none)
|
|
}
|
|
}},
|
|
{"credits keep their order and are counted", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
b := mustCreateAuthor(t, authors, "B", "b", nil)
|
|
c := mustCreateAuthor(t, authors, "C", "c", nil)
|
|
first := mustCreateCreditedArticle(t, db, "First", c.ID, a.ID, b.ID)
|
|
mustCreateCreditedArticle(t, db, "Second", a.ID)
|
|
|
|
if got := creditedIDs(t, db, first.ID); !reflect.DeepEqual(got, []uint32{c.ID, a.ID, b.ID}) {
|
|
t.Errorf("order = %v", got)
|
|
}
|
|
counted, _ := authors.Get(a.ID)
|
|
if counted.ArticleCount != 2 {
|
|
t.Errorf("count = %d", counted.ArticleCount)
|
|
}
|
|
reordered := []uint32{b.ID, c.ID}
|
|
if _, err := persistence.NewArticleRepository(db).Update(first.ID, article.Update{AuthorIDs: &reordered}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := creditedIDs(t, db, first.ID); !reflect.DeepEqual(got, reordered) {
|
|
t.Errorf("after replace = %v", got)
|
|
}
|
|
}},
|
|
{"an author is credited at most once on an article", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
created := mustCreateCreditedArticle(t, db, "First", a.ID)
|
|
duplicated := []uint32{a.ID, a.ID}
|
|
|
|
_, err := persistence.NewArticleRepository(db).Update(created.ID, article.Update{AuthorIDs: &duplicated})
|
|
|
|
if err == nil {
|
|
t.Errorf("expected the unique pair to be refused")
|
|
}
|
|
if got := creditedIDs(t, db, created.ID); !reflect.DeepEqual(got, []uint32{a.ID}) {
|
|
t.Errorf("credits = %v", got)
|
|
}
|
|
}},
|
|
{"deleting an article removes its credits and keeps the author", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
first := mustCreateCreditedArticle(t, db, "First", a.ID)
|
|
mustCreateCreditedArticle(t, db, "Second", a.ID)
|
|
|
|
if err := persistence.NewArticleRepository(db).Delete(first.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
kept, _ := authors.Get(a.ID)
|
|
var credits int64
|
|
db.Model(&entity.ArticleAuthor{}).Where("article_id = ?", first.ID).Count(&credits)
|
|
if kept.ArticleCount != 1 || credits != 0 {
|
|
t.Errorf("count %d credits %d", kept.ArticleCount, credits)
|
|
}
|
|
}},
|
|
{"reassigning keeps the position and never duplicates", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
b := mustCreateAuthor(t, authors, "B", "b", nil)
|
|
c := mustCreateAuthor(t, authors, "C", "c", nil)
|
|
d := mustCreateAuthor(t, authors, "D", "d", nil)
|
|
positioned := mustCreateCreditedArticle(t, db, "Positioned", a.ID, b.ID, c.ID)
|
|
shared := mustCreateCreditedArticle(t, db, "Shared", b.ID, d.ID)
|
|
|
|
if err := authors.DeleteMovingCredits(b.ID, &d.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if got := creditedIDs(t, db, positioned.ID); !reflect.DeepEqual(got, []uint32{a.ID, d.ID, c.ID}) {
|
|
t.Errorf("positioned = %v", got)
|
|
}
|
|
if got := creditedIDs(t, db, shared.ID); !reflect.DeepEqual(got, []uint32{d.ID}) {
|
|
t.Errorf("shared = %v", got)
|
|
}
|
|
if _, err := authors.Get(b.ID); !errors.Is(err, author.ErrAuthorNotFound) {
|
|
t.Errorf("the author still exists: %v", err)
|
|
}
|
|
}},
|
|
{"deleting with no destination removes only that credit", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
b := mustCreateAuthor(t, authors, "B", "b", nil)
|
|
c := mustCreateAuthor(t, authors, "C", "c", nil)
|
|
shared := mustCreateCreditedArticle(t, db, "Shared", a.ID, b.ID, c.ID)
|
|
alone := mustCreateCreditedArticle(t, db, "Alone", b.ID)
|
|
|
|
if err := authors.DeleteUncrediting(b.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if got := creditedIDs(t, db, shared.ID); !reflect.DeepEqual(got, []uint32{a.ID, c.ID}) {
|
|
t.Errorf("shared = %v", got)
|
|
}
|
|
if got := creditedIDs(t, db, alone.ID); len(got) != 0 {
|
|
t.Errorf("alone = %v", got)
|
|
}
|
|
}},
|
|
{"avatars are counted, cleared and repointed", func(t *testing.T, db *gorm.DB, authors *persistence.AuthorRepository) {
|
|
images := newContractRepositories(db)
|
|
kept := mustCreateImage(t, images, "a.png", "hash-a")
|
|
copied := mustCreateImage(t, images, "b.png", "hash-a")
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
a.AvatarID = &copied.ID
|
|
if _, err := authors.Update(a); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
usage, _ := authors.AvatarUsage()
|
|
repointed, err := authors.RepointAvatar([]uint32{copied.ID}, kept.ID)
|
|
afterRepoint, _ := authors.Get(a.ID)
|
|
cleared, clearErr := authors.ClearAvatar(kept.ID)
|
|
afterClear, _ := authors.Get(a.ID)
|
|
restoreErr := authors.AssignAvatar(cleared, kept.ID)
|
|
restored, _ := authors.Get(a.ID)
|
|
|
|
if usage[copied.ID] != 1 || err != nil || repointed != 1 || *afterRepoint.AvatarID != kept.ID {
|
|
t.Fatalf("usage %v repoint %d %v %+v", usage, repointed, err, afterRepoint)
|
|
}
|
|
if clearErr != nil || len(cleared) != 1 || afterClear.AvatarID != nil || restoreErr != nil || *restored.AvatarID != kept.ID {
|
|
t.Errorf("clear %v %v %+v restore %v %+v", cleared, clearErr, afterClear, restoreErr, restored)
|
|
}
|
|
}},
|
|
}
|
|
for _, backend := range backends {
|
|
t.Run(backend.name, func(t *testing.T) {
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
db := backend.open(t)
|
|
c.run(t, db, persistence.NewAuthorRepository(db))
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuthorRepositoryIsAtomicOnSQLite(t *testing.T) {
|
|
t.Run("Reassign and delete are all-or-nothing", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
b := mustCreateAuthor(t, authors, "B", "b", nil)
|
|
first := mustCreateCreditedArticle(t, db, "First", a.ID)
|
|
if err := db.Exec("CREATE TRIGGER refuse_author_delete BEFORE DELETE ON authors BEGIN SELECT RAISE(ABORT, 'refused'); END").Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := authors.DeleteMovingCredits(a.ID, &b.ID); err == nil {
|
|
t.Fatal("expected the delete to fail")
|
|
}
|
|
|
|
if got := creditedIDs(t, db, first.ID); !reflect.DeepEqual(got, []uint32{a.ID}) {
|
|
t.Errorf("credits = %v", got)
|
|
}
|
|
if still, err := authors.Get(a.ID); err != nil || still.ArticleCount != 1 {
|
|
t.Errorf("author %+v %v", still, err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAuthorRepositoryEdges(t *testing.T) {
|
|
t.Run("A searched list pages through its matches and returns them", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
for i := 1; i <= 5; i++ {
|
|
mustCreateAuthor(t, authors, fmt.Sprintf("Writer %d", i), fmt.Sprintf("writer-%d", i), nil)
|
|
}
|
|
mustCreateAuthor(t, authors, "Other", "other", nil)
|
|
|
|
first, _ := authors.List(author.ListQuery{Q: "writer", Page: 1, Size: 2})
|
|
second, _ := authors.List(author.ListQuery{Q: "writer", Page: 2, Size: 2})
|
|
beyond, _ := authors.List(author.ListQuery{Q: "writer", Page: 4, Size: 2})
|
|
|
|
if first.Total != 5 || len(first.Items) != 2 || first.Items[0].Name != "Writer 5" || first.Items[1].Name != "Writer 4" {
|
|
t.Errorf("first %+v", first)
|
|
}
|
|
if second.Total != 5 || len(second.Items) != 2 || second.Items[0].Name != "Writer 3" || second.Items[1].Name != "Writer 2" {
|
|
t.Errorf("second %+v", second)
|
|
}
|
|
if beyond.Total != 5 || len(beyond.Items) != 0 {
|
|
t.Errorf("beyond %+v", beyond)
|
|
}
|
|
})
|
|
|
|
t.Run("A write failure that is not a conflict is reported", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
if err := db.Exec("CREATE TRIGGER refuse_author_insert BEFORE INSERT ON authors BEGIN SELECT RAISE(ABORT, 'refused'); END").Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
created, err := authors.Create(author.Author{Name: "A", Slug: "a", SocialLinks: []author.SocialLink{}})
|
|
|
|
if err == nil || errors.Is(err, author.ErrSlugTaken) || created.ID != 0 {
|
|
t.Errorf("created %+v err %v", created, err)
|
|
}
|
|
})
|
|
|
|
t.Run("Deleting toward a missing destination changes nothing", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
first := mustCreateCreditedArticle(t, db, "First", a.ID)
|
|
missing := uint32(999)
|
|
|
|
toMissing := authors.DeleteMovingCredits(a.ID, &missing)
|
|
fromMissing := authors.DeleteMovingCredits(missing, nil)
|
|
|
|
if !errors.Is(toMissing, author.ErrAuthorNotFound) || !errors.Is(fromMissing, author.ErrAuthorNotFound) {
|
|
t.Errorf("errors %v %v", toMissing, fromMissing)
|
|
}
|
|
if got := creditedIDs(t, db, first.ID); !reflect.DeepEqual(got, []uint32{a.ID}) {
|
|
t.Errorf("credits = %v", got)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAuthorRepositoryPaging(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
for i := 1; i <= 5; i++ {
|
|
mustCreateAuthor(t, authors, fmt.Sprintf("Writer %d", i), fmt.Sprintf("writer-%d", i), nil)
|
|
}
|
|
for _, q := range []string{"", "writer"} {
|
|
empty, emptyErr := authors.List(author.ListQuery{Q: q, Page: 1, Size: 0})
|
|
if emptyErr != nil || len(empty.Items) != 0 || empty.Total != 5 {
|
|
t.Errorf("q=%q size 0 %+v %v", q, empty, emptyErr)
|
|
}
|
|
second, _ := authors.List(author.ListQuery{Q: q, Page: 2, Size: 2})
|
|
last, _ := authors.List(author.ListQuery{Q: q, Page: 3, Size: 2})
|
|
beyond, _ := authors.List(author.ListQuery{Q: q, Page: 4, Size: 2})
|
|
if len(second.Items) != 2 || second.Items[0].Name != "Writer 3" {
|
|
t.Errorf("q=%q second %+v", q, second)
|
|
}
|
|
if len(last.Items) != 1 || last.Items[0].Name != "Writer 1" || last.Total != 5 {
|
|
t.Errorf("q=%q last %+v", q, last)
|
|
}
|
|
if len(beyond.Items) != 0 || beyond.Total != 5 {
|
|
t.Errorf("q=%q beyond %+v", q, beyond)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAuthorMigration(t *testing.T) {
|
|
t.Run("The new tables are migrated and existing articles get no authors", func(t *testing.T) {
|
|
db := openUnmigratedSQLite(t)
|
|
if err := db.AutoMigrate(&entity.Article{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for i := 0; i < 4; i++ {
|
|
if err := db.Create(&entity.Article{Title: fmt.Sprintf("Old %d", i), Body: "Body"}).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
if err := database.Migrate(db, migrationPublicURL); err != nil {
|
|
t.Fatalf("migrate: %v", err)
|
|
}
|
|
if err := database.Migrate(db, migrationPublicURL); err != nil {
|
|
t.Fatalf("second migrate: %v", err)
|
|
}
|
|
|
|
var authors, credits int64
|
|
db.Model(&entity.Author{}).Count(&authors)
|
|
db.Model(&entity.ArticleAuthor{}).Count(&credits)
|
|
if authors != 0 || credits != 0 || !db.Migrator().HasTable("authors") || !db.Migrator().HasTable("article_authors") {
|
|
t.Errorf("authors %d credits %d", authors, credits)
|
|
}
|
|
found, err := persistence.NewArticleRepository(db).FindPage(article.Filters{Page: 1, Size: 10})
|
|
if err != nil || found.Total != 4 || len(found.Items[0].Authors) != 0 {
|
|
t.Errorf("articles %+v %v", found, err)
|
|
}
|
|
})
|
|
|
|
t.Run("The unique indexes exist", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
for _, name := range []string{"idx_authors_slug", "idx_authors_user_id", "idx_article_authors_pair"} {
|
|
table := "authors"
|
|
if name == "idx_article_authors_pair" {
|
|
table = "article_authors"
|
|
}
|
|
if !db.Migrator().HasIndex(table, name) {
|
|
t.Errorf("missing index %s", name)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAuthorRepositoryGuards(t *testing.T) {
|
|
t.Run("Deleting without a destination refuses a credited author", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
first := mustCreateCreditedArticle(t, db, "First", a.ID)
|
|
|
|
err := authors.DeleteMovingCredits(a.ID, nil)
|
|
|
|
if !errors.Is(err, author.ErrAuthorHasArticles) {
|
|
t.Errorf("err = %v", err)
|
|
}
|
|
if got := creditedIDs(t, db, first.ID); !reflect.DeepEqual(got, []uint32{a.ID}) {
|
|
t.Errorf("credits = %v", got)
|
|
}
|
|
if _, err := authors.Get(a.ID); err != nil {
|
|
t.Errorf("author gone: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Deleting without a destination removes an uncredited author", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
a := mustCreateAuthor(t, authors, "A", "a", nil)
|
|
|
|
if err := authors.DeleteMovingCredits(a.ID, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := authors.Get(a.ID); !errors.Is(err, author.ErrAuthorNotFound) {
|
|
t.Errorf("get = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("A huge page number lists nothing and keeps the total", func(t *testing.T) {
|
|
db := openContractSQLite(t)
|
|
authors := persistence.NewAuthorRepository(db)
|
|
for i := 1; i <= 3; i++ {
|
|
mustCreateAuthor(t, authors, fmt.Sprintf("Writer %d", i), fmt.Sprintf("writer-%d", i), nil)
|
|
}
|
|
huge := int(^uint(0) >> 1)
|
|
|
|
plain, plainErr := authors.List(author.ListQuery{Page: huge, Size: 100})
|
|
searched, searchErr := authors.List(author.ListQuery{Q: "writer", Page: huge, Size: 100})
|
|
|
|
if plainErr != nil || plain.Total != 3 || len(plain.Items) != 0 {
|
|
t.Errorf("plain %+v %v", plain, plainErr)
|
|
}
|
|
if searchErr != nil || searched.Total != 3 || len(searched.Items) != 0 {
|
|
t.Errorf("searched %+v %v", searched, searchErr)
|
|
}
|
|
})
|
|
}
|