166 lines
6.2 KiB
Go
166 lines
6.2 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/article"
|
|
"RenewCMS/internal/domain/site"
|
|
"RenewCMS/internal/infrastructure/useCases"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestSiteDomainRules(t *testing.T) {
|
|
t.Run("NormalizeBaseURL accepts what the rule allows and strips the trailing slash", func(t *testing.T) {
|
|
accepted := map[string]string{
|
|
"https://shop.example.com": "https://shop.example.com",
|
|
"https://shop.example.com/": "https://shop.example.com",
|
|
"https://SHOP.example.com:8443": "https://shop.example.com:8443",
|
|
"http://localhost": "http://localhost",
|
|
"http://[::1]:8080/": "http://[::1]:8080",
|
|
"HTTPS://shop.example.com": "https://shop.example.com",
|
|
}
|
|
for sent, stored := range accepted {
|
|
if got, err := site.NormalizeBaseURL(sent); err != nil || got != stored {
|
|
t.Errorf("%q gave %q, %v; expected %q", sent, got, err, stored)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("NormalizeBaseURL refuses everything else", func(t *testing.T) {
|
|
for _, sent := range []string{"", "http://shop.example.com", "https://", "https://shop.example.com/x", "https://shop.example.com?x", "https://shop.example.com/#top", "https://u:p@shop.example.com", "ftp://shop.example.com", "shop.example.com", "localhost:8080", "https://shop example.com"} {
|
|
if got, err := site.NormalizeBaseURL(sent); !errors.Is(err, site.ErrInvalidSiteURL) {
|
|
t.Errorf("%q gave %q, %v; expected ErrInvalidSiteURL", sent, got, err)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("SeedBaseURL drops the path and upgrades non-loopback http", func(t *testing.T) {
|
|
accepted := map[string]string{
|
|
"https://www.example.com/blog": "https://www.example.com",
|
|
"http://www.example.com": "https://www.example.com",
|
|
"http://localhost:5173": "http://localhost:5173",
|
|
"http://[::1]:8080/x": "http://[::1]:8080",
|
|
"https://user@www.example.com": "https://www.example.com",
|
|
}
|
|
for sent, stored := range accepted {
|
|
if got, err := site.SeedBaseURL(sent); err != nil || got != stored {
|
|
t.Errorf("%q gave %q, %v; expected %q", sent, got, err, stored)
|
|
}
|
|
}
|
|
for _, sent := range []string{"", "://not a url", "ftp://example.com", "example.com"} {
|
|
if _, err := site.SeedBaseURL(sent); err == nil {
|
|
t.Errorf("%q must be refused", sent)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("NormalizeLocale keeps valid tags and turns empty into none", func(t *testing.T) {
|
|
for _, locale := range []string{"en", "fr-CA", "zh-Hant-TW", "yue"} {
|
|
if got, err := site.NormalizeLocale(&locale); err != nil || got == nil || *got != locale {
|
|
t.Errorf("%q gave %v, %v", locale, got, err)
|
|
}
|
|
}
|
|
empty := ""
|
|
if got, err := site.NormalizeLocale(&empty); err != nil || got != nil {
|
|
t.Errorf("empty gave %v, %v", got, err)
|
|
}
|
|
if got, err := site.NormalizeLocale(nil); err != nil || got != nil {
|
|
t.Errorf("nil gave %v, %v", got, err)
|
|
}
|
|
for _, locale := range []string{"english", "fr_FR", "f", "FR", "fr-"} {
|
|
if _, err := site.NormalizeLocale(&locale); !errors.Is(err, site.ErrInvalidLocale) {
|
|
t.Errorf("%q must be refused", locale)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("IsValidKey enforces the pattern and the length", func(t *testing.T) {
|
|
valid := []string{"ab", "shop", "my-shop-2", "a1", strings.Repeat("a", 32)}
|
|
invalid := []string{"", "a", "Shop", "-shop", "shop-", "my--shop", "my_shop", strings.Repeat("a", 33)}
|
|
for _, key := range valid {
|
|
if !site.IsValidKey(key) {
|
|
t.Errorf("%q must be valid", key)
|
|
}
|
|
}
|
|
for _, key := range invalid {
|
|
if site.IsValidKey(key) {
|
|
t.Errorf("%q must be invalid", key)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSiteUseCaseRules(t *testing.T) {
|
|
t.Run("Creating an article assigns it to the default site", func(t *testing.T) {
|
|
repo := newMockArticleRepo()
|
|
created, err := useCases.NewCreateArticleUseCase(repo, &fakeBodyRenderer{}, discardRecorder, plainSites()).CreateArticle(testCtx, useCases.CreateArticleCommand{Title: "Valid Title"})
|
|
if err != nil || created.SiteID != 1 {
|
|
t.Errorf("created %+v, %v", created, err)
|
|
}
|
|
})
|
|
|
|
t.Run("Creating an article fails when no default site can be read", func(t *testing.T) {
|
|
repo := newMockArticleRepo()
|
|
sites := newMockSiteRepo(repo)
|
|
uc := useCases.NewCreateArticleUseCase(repo, &fakeBodyRenderer{}, discardRecorder, sites)
|
|
|
|
_, err := uc.CreateArticle(testCtx, useCases.CreateArticleCommand{Title: "Valid Title"})
|
|
|
|
if !errors.Is(err, site.ErrSiteNotFound) || repo.createCalled {
|
|
t.Errorf("err = %v, create called = %v", err, repo.createCalled)
|
|
}
|
|
})
|
|
|
|
t.Run("A destination site that does not exist leaves the article untouched", func(t *testing.T) {
|
|
repo := newMockArticleRepo()
|
|
repo.articles[1] = article.Article{ID: 1, Title: "Valid Title", SiteID: 1}
|
|
sites := newMockSiteRepo(repo)
|
|
sites.seed(1, "Main", "main", true)
|
|
uc := useCases.NewUpdateArticleUseCase(repo, &fakeBodyRenderer{}, discardRecorder, sites)
|
|
missing := uint32(9)
|
|
|
|
_, err := uc.Update(testCtx, 1, useCases.UpdateArticleCommand{SiteID: &missing})
|
|
|
|
if !errors.Is(err, site.ErrSiteNotFound) || repo.articles[1].SiteID != 1 {
|
|
t.Errorf("err = %v, stored %+v", err, repo.articles[1])
|
|
}
|
|
})
|
|
|
|
t.Run("Deleting a site validates the destination before touching anything", func(t *testing.T) {
|
|
repo := newMockArticleRepo()
|
|
sites := newMockSiteRepo(repo)
|
|
sites.seed(1, "Main", "main", true)
|
|
sites.seed(2, "Shop", "shop", false)
|
|
repo.articles[1] = article.Article{ID: 1, Title: "Valid Title", SiteID: 2}
|
|
uc := useCases.NewDeleteSiteUseCase(sites, discardRecorder)
|
|
self := uint32(2)
|
|
|
|
for name, command := range map[string]useCases.DeleteSiteCommand{
|
|
"itself": {ID: 2, ReassignTo: &self},
|
|
"invalid": {ID: 2, ReassignInvalid: true},
|
|
"zero": {ID: 2, ReassignTo: idPointer(0)},
|
|
} {
|
|
if err := uc.Delete(testCtx, command); !errors.Is(err, site.ErrInvalidReassign) {
|
|
t.Errorf("%s: err = %v", name, err)
|
|
}
|
|
}
|
|
if sites.deleteCalls != 0 {
|
|
t.Errorf("the repository was called %d times", sites.deleteCalls)
|
|
}
|
|
})
|
|
|
|
t.Run("Editing a site with is_default is refused", func(t *testing.T) {
|
|
repo := newMockArticleRepo()
|
|
sites := newMockSiteRepo(repo)
|
|
sites.seed(2, "Shop", "shop", false)
|
|
uc := useCases.NewUpdateSiteUseCase(sites, newMockImageRepo(), discardRecorder)
|
|
flag := true
|
|
|
|
_, err := uc.Update(testCtx, 2, site.Patch{IsDefault: &flag})
|
|
|
|
if !errors.Is(err, site.ErrUseSetDefault) {
|
|
t.Errorf("err = %v", err)
|
|
}
|
|
})
|
|
}
|