506 lines
19 KiB
Go
506 lines
19 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/localization"
|
|
"net/http"
|
|
"reflect"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
var languagesReadKeys = []string{"available", "default", "languages", "needs_setup", "revision"}
|
|
|
|
func TestSiteLanguagesReading(t *testing.T) {
|
|
t.Run("Read the languages", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
|
|
rec := e.as(t, readerUserID, http.MethodGet, "/v1/site/journal/languages", "")
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status %d: %s", rec.Code, rec.Body)
|
|
}
|
|
if keys := keysOf(decodeFields(t, rec)); !reflect.DeepEqual(keys, languagesReadKeys) {
|
|
t.Errorf("keys = %v", keys)
|
|
}
|
|
view := decodeLanguagesView(t, rec)
|
|
if view.Revision == "" || view.Default == nil || *view.Default != "en" || view.NeedsSetup {
|
|
t.Errorf("header = %+v", view)
|
|
}
|
|
if !reflect.DeepEqual(view.tags(), []string{"en", "ar", "de", "fr", "en-US", "es"}) {
|
|
t.Errorf("order = %v", view.tags())
|
|
}
|
|
counts := map[string][2]int{"en": {7, 6}, "fr": {4, 2}, "de": {4, 3}, "ar": {1, 0}, "es": {1, 0}, "en-US": {0, 0}}
|
|
for _, entry := range view.Languages {
|
|
if got := [2]int{entry.VersionCount, entry.PublishedCount}; got != counts[entry.Lang] {
|
|
t.Errorf("%s counts = %v", entry.Lang, got)
|
|
}
|
|
}
|
|
if available := view.Available; len(available) == 0 || !slices.ContainsFunc(available, func(o struct {
|
|
Lang string `json:"lang"`
|
|
Substitute *string `json:"substitute"`
|
|
}) bool {
|
|
return o.Lang == "pt-PT" && o.Substitute != nil && *o.Substitute == "pt"
|
|
}) {
|
|
t.Errorf("available = %+v", available)
|
|
}
|
|
})
|
|
|
|
t.Run("Read access", func(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
user uint32
|
|
key string
|
|
status int
|
|
}{
|
|
{"an anonymous client", 0, "journal", http.StatusUnauthorized},
|
|
{"a reader", readerUserID, "journal", http.StatusOK},
|
|
{"an owner", apiKeyOwnerId, "journal", http.StatusOK},
|
|
{"an owner on an unknown site", apiKeyOwnerId, "nowhere", http.StatusNotFound},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
rec := e.as(t, c.user, http.MethodGet, "/v1/site/"+c.key+"/languages", "")
|
|
if rec.Code != c.status {
|
|
t.Fatalf("status %d: %s", rec.Code, rec.Body)
|
|
}
|
|
if c.status == http.StatusNotFound && bodyText(rec) != "site_not_found" {
|
|
t.Errorf("body = %q", bodyText(rec))
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Social locale states", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.sites.seed(5, "Atelier", "atelier", false)
|
|
fr := "fr_FR"
|
|
e.seedRows(5,
|
|
localization.Row{Tag: "en", IsDefault: true, Enabled: true, Confirmed: true},
|
|
localization.Row{Tag: "en-GB", Enabled: true},
|
|
localization.Row{Tag: "fr", Enabled: true, SocialLocale: &fr},
|
|
localization.Row{Tag: "pt-BR", Enabled: true},
|
|
)
|
|
cases := []struct {
|
|
lang string
|
|
state string
|
|
explicit *string
|
|
effective *string
|
|
}{
|
|
{"en-GB", "derived", nil, localeOf("en_GB")},
|
|
{"pt-BR", "derived", nil, localeOf("pt_BR")},
|
|
{"fr", "set", &fr, &fr},
|
|
{"en", "not_set", nil, nil},
|
|
}
|
|
rec := e.owner(t, http.MethodGet, "/v1/site/atelier/languages", "")
|
|
view := decodeLanguagesView(t, rec)
|
|
for _, c := range cases {
|
|
t.Run(c.lang, func(t *testing.T) {
|
|
for _, entry := range view.Languages {
|
|
if entry.Lang != c.lang {
|
|
continue
|
|
}
|
|
if entry.State != c.state || !sameText(entry.SocialLocale, c.explicit) {
|
|
t.Errorf("entry = %+v", entry)
|
|
}
|
|
row := localization.Row{Tag: entry.Lang, SocialLocale: entry.SocialLocale}
|
|
if !sameText(localization.EffectiveSocialLocale(row, nil), c.effective) {
|
|
t.Errorf("effective = %v", localization.EffectiveSocialLocale(row, nil))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("A bare tag borrows the region of Site.Locale", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.sites.seed(5, "Atelier", "atelier", false)
|
|
gb := "en-GB"
|
|
stored := e.sites.sites[5]
|
|
stored.Locale = &gb
|
|
e.sites.sites[5] = stored
|
|
e.seedRows(5, localization.Row{Tag: "en", IsDefault: true, Enabled: true, Confirmed: true})
|
|
|
|
view := decodeLanguagesView(t, e.owner(t, http.MethodGet, "/v1/site/atelier/languages", ""))
|
|
|
|
if view.Languages[0].State != "derived" {
|
|
t.Errorf("state = %q", view.Languages[0].State)
|
|
}
|
|
row := localization.Row{Tag: "en"}
|
|
if !sameText(localization.EffectiveSocialLocale(row, &gb), localeOf("en_GB")) {
|
|
t.Errorf("effective = %v", localization.EffectiveSocialLocale(row, &gb))
|
|
}
|
|
})
|
|
|
|
t.Run("No region anywhere stays not set", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.sites.seed(5, "Atelier", "atelier", false)
|
|
bare := "en"
|
|
stored := e.sites.sites[5]
|
|
stored.Locale = &bare
|
|
e.sites.sites[5] = stored
|
|
e.seedRows(5, localization.Row{Tag: "en", IsDefault: true, Enabled: true, Confirmed: true})
|
|
|
|
view := decodeLanguagesView(t, e.owner(t, http.MethodGet, "/v1/site/atelier/languages", ""))
|
|
|
|
if view.Languages[0].State != "not_set" || localization.EffectiveSocialLocale(localization.Row{Tag: "en"}, &bare) != nil {
|
|
t.Errorf("state = %q", view.Languages[0].State)
|
|
}
|
|
})
|
|
|
|
t.Run("A site that still needs setup", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.sites.seed(2, "Notes", "notes", false)
|
|
before := e.store.replaceCalls
|
|
|
|
view := decodeLanguagesView(t, e.as(t, readerUserID, http.MethodGet, "/v1/site/notes/languages", ""))
|
|
put := e.owner(t, http.MethodPut, "/v1/site/notes/languages", languagesBody("any", "en", entryJSON("en", true, "null")))
|
|
|
|
if !view.NeedsSetup {
|
|
t.Errorf("needs_setup = false")
|
|
}
|
|
expectSiteStatusAndBody(t, put, http.StatusConflict, "setup_required")
|
|
if e.store.replaceCalls != before {
|
|
t.Errorf("something was stored")
|
|
}
|
|
})
|
|
|
|
t.Run("Sites created after the migration have no language row", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.sites.seed(2, "Fresh", "fresh", false)
|
|
|
|
view := decodeLanguagesView(t, e.owner(t, http.MethodGet, "/v1/site/fresh/languages", ""))
|
|
|
|
if !view.NeedsSetup || len(view.Languages) != 0 || view.Default != nil {
|
|
t.Errorf("view = %+v", view)
|
|
}
|
|
})
|
|
}
|
|
|
|
func sameText(left *string, right *string) bool {
|
|
if left == nil || right == nil {
|
|
return left == right
|
|
}
|
|
return *left == *right
|
|
}
|
|
|
|
func TestSiteLanguagesWriting(t *testing.T) {
|
|
put := func(e *localizationEnv, t *testing.T, defaultTag string, entries []string) (string, string) {
|
|
t.Helper()
|
|
revision := e.revision(t, "journal")
|
|
rec := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(revision, defaultTag, entries...))
|
|
return rec.Body.String(), http.StatusText(rec.Code)
|
|
}
|
|
_ = put
|
|
|
|
changes := []struct {
|
|
name string
|
|
def string
|
|
entries []string
|
|
check func(t *testing.T, view languagesView)
|
|
}{
|
|
{"fr added with enabled true", "en", journalEntries(map[string]string{"fr": entryJSON("fr", true, `"fr_FR"`)}), func(t *testing.T, v languagesView) {
|
|
if countTag(v, "fr") != 1 || !findLanguage(t, v, "fr").Enabled {
|
|
t.Errorf("fr = %+v", v.tags())
|
|
}
|
|
}},
|
|
{"pt-br added (lowercase) as enabled", "en", append(journalEntries(nil), entryJSON("pt-br", true, "null")), func(t *testing.T, v languagesView) {
|
|
if countTag(v, "pt-BR") != 1 || countTag(v, "pt-br") != 0 {
|
|
t.Errorf("tags = %v", v.tags())
|
|
}
|
|
}},
|
|
{"default fr", "fr", journalEntries(nil), func(t *testing.T, v languagesView) {
|
|
if !findLanguage(t, v, "fr").IsDefault || findLanguage(t, v, "en").IsDefault || !findLanguage(t, v, "en").Enabled {
|
|
t.Errorf("view = %+v", v.Languages)
|
|
}
|
|
}},
|
|
{"de enabled false", "en", journalEntries(map[string]string{"de": entryJSON("de", false, "null")}), func(t *testing.T, v languagesView) {
|
|
de := findLanguage(t, v, "de")
|
|
if de.Enabled || de.VersionCount != 4 || de.PublishedCount != 3 {
|
|
t.Errorf("de = %+v", de)
|
|
}
|
|
}},
|
|
{"es enabled true", "en", journalEntries(map[string]string{"es": entryJSON("es", true, "null")}), func(t *testing.T, v languagesView) {
|
|
es := findLanguage(t, v, "es")
|
|
if !es.Enabled || es.VersionCount != 1 {
|
|
t.Errorf("es = %+v", es)
|
|
}
|
|
}},
|
|
{"en-US omitted", "en", journalEntries(nil, "en-US"), func(t *testing.T, v languagesView) {
|
|
if countTag(v, "en-US") != 0 {
|
|
t.Errorf("tags = %v", v.tags())
|
|
}
|
|
}},
|
|
{"fr social_locale fr_CA", "en", journalEntries(map[string]string{"fr": entryJSON("fr", true, `"fr_CA"`)}), func(t *testing.T, v languagesView) {
|
|
fr := findLanguage(t, v, "fr")
|
|
if fr.State != "set" || fr.SocialLocale == nil || *fr.SocialLocale != "fr_CA" {
|
|
t.Errorf("fr = %+v", fr)
|
|
}
|
|
}},
|
|
{"fr social_locale null", "en", journalEntries(map[string]string{"fr": entryJSON("fr", true, "null")}), func(t *testing.T, v languagesView) {
|
|
if findLanguage(t, v, "fr").State != "not_set" {
|
|
t.Errorf("fr = %+v", findLanguage(t, v, "fr"))
|
|
}
|
|
}},
|
|
}
|
|
for _, c := range changes {
|
|
t.Run("Changing the set/"+c.name, func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
articlesBefore := len(e.articles.articles)
|
|
revision := e.revision(t, "journal")
|
|
|
|
rec := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(revision, c.def, c.entries...))
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status %d: %s", rec.Code, rec.Body)
|
|
}
|
|
c.check(t, decodeLanguagesView(t, rec))
|
|
if len(e.articles.articles) != articlesBefore {
|
|
t.Errorf("articles changed")
|
|
}
|
|
for _, stored := range e.articles.articles {
|
|
if stored.Lang == "" {
|
|
t.Errorf("an article lost its language")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
rejections := []struct {
|
|
name string
|
|
def string
|
|
entries func() []string
|
|
status int
|
|
code string
|
|
}{
|
|
{"default en with en enabled false", "en", func() []string {
|
|
return journalEntries(map[string]string{"en": entryJSON("en", false, "null")})
|
|
}, 422, "default_not_enabled"},
|
|
{"default ja", "ja", func() []string { return journalEntries(nil) }, 422, "default_not_enabled"},
|
|
{"every language enabled false", "en", func() []string {
|
|
entries := []string{}
|
|
for _, tag := range []string{"en", "fr", "de", "ar", "es", "en-US"} {
|
|
entries = append(entries, entryJSON(tag, false, "null"))
|
|
}
|
|
return entries
|
|
}, 422, "no_enabled_language"},
|
|
{"languages []", "en", func() []string { return nil }, 422, "no_enabled_language"},
|
|
{"es omitted (1 version)", "en", func() []string { return journalEntries(nil, "es") }, 409, "language_in_use"},
|
|
{"ar omitted (1 draft or offline version)", "en", func() []string { return journalEntries(nil, "ar") }, 409, "language_in_use"},
|
|
{"en omitted", "en", func() []string { return journalEntries(nil, "en") }, 422, "default_not_enabled"},
|
|
{"a language english", "en", func() []string { return append(journalEntries(nil), entryJSON("english", true, "null")) }, 422, "invalid_language"},
|
|
{"a language xx", "en", func() []string { return append(journalEntries(nil), entryJSON("xx", true, "null")) }, 422, "unsupported_language"},
|
|
{"a language pt-PT", "en", func() []string { return append(journalEntries(nil), entryJSON("pt-PT", true, "null")) }, 422, "unsupported_language"},
|
|
{"the same tag twice", "en", func() []string {
|
|
return append(journalEntries(nil), entryJSON("fr", true, "null"), entryJSON("FR", true, "null"))
|
|
}, 422, "duplicate_language"},
|
|
{"fr social_locale fr-FR", "en", func() []string { return socialOnFrench(`"fr-FR"`) }, 422, "invalid_social_locale"},
|
|
{"fr social_locale fr", "en", func() []string { return socialOnFrench(`"fr"`) }, 422, "invalid_social_locale"},
|
|
{"fr social_locale empty", "en", func() []string { return socialOnFrench(`""`) }, 422, "invalid_social_locale"},
|
|
{"fr social_locale pt_BR", "en", func() []string { return socialOnFrench(`"pt_BR"`) }, 422, "invalid_social_locale"},
|
|
{"fr default, de disabled and es omitted", "fr", func() []string {
|
|
return journalEntries(map[string]string{"de": entryJSON("de", false, "null")}, "es")
|
|
}, 409, "language_in_use"},
|
|
}
|
|
for _, c := range rejections {
|
|
t.Run("Rules that reject a change/"+c.name, func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
rowsBefore, articlesBefore := e.store.snapshot()
|
|
revision := e.revision(t, "journal")
|
|
|
|
rec := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(revision, c.def, c.entries()...))
|
|
|
|
expectSiteStatusAndBody(t, rec, c.status, c.code)
|
|
rowsAfter, articlesAfter := e.store.snapshot()
|
|
if !reflect.DeepEqual(rowsBefore, rowsAfter) || !reflect.DeepEqual(articlesBefore, articlesAfter) || e.store.replaceCalls != 0 {
|
|
t.Errorf("something was stored")
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("Rules that reject a change/no revision key", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
rec := e.owner(t, http.MethodPut, "/v1/site/journal/languages", `{"default":"en","languages":[`+entryJSON("en", true, "null")+`]}`)
|
|
expectSiteStatusAndBody(t, rec, http.StatusBadRequest, "The request cannot be processed due to a mismatch in the format of the body.")
|
|
})
|
|
|
|
t.Run("Rules that reject a change/malformed JSON", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
rec := e.owner(t, http.MethodPut, "/v1/site/journal/languages", `{not json`)
|
|
expectSiteStatusAndBody(t, rec, http.StatusBadRequest, "The request cannot be processed due to a mismatch in the format of the body.")
|
|
})
|
|
|
|
t.Run("Social locale format and language part", func(t *testing.T) {
|
|
cases := []struct {
|
|
tag string
|
|
social string
|
|
valid bool
|
|
}{
|
|
{"fr", "fr_FR", true},
|
|
{"fr", "fr_CA", true},
|
|
{"fr", "pt_BR", false},
|
|
{"fr-CA", "fr_CA", true},
|
|
{"ar", "ara_EG", false},
|
|
{"fr", "fr_F", false},
|
|
{"fr", "fr__FR", false},
|
|
{"fr", "fr_F1", false},
|
|
}
|
|
for _, c := range cases {
|
|
social := c.social
|
|
_, err := localization.NormalizeSocialLocale(c.tag, &social)
|
|
if (err == nil) != c.valid {
|
|
t.Errorf("%s on %s: err = %v", c.social, c.tag, err)
|
|
}
|
|
}
|
|
if normalized, err := localization.NormalizeSocialLocale("fr", localeOf("fr_fr")); err != nil || *normalized != "fr_FR" {
|
|
t.Errorf("normalized = %v, %v", normalized, err)
|
|
}
|
|
})
|
|
|
|
t.Run("A stale revision is refused", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
stale := e.revision(t, "journal")
|
|
other := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(stale, "en", journalEntries(map[string]string{"fr": entryJSON("fr", true, `"fr_CA"`)})...))
|
|
if other.Code != http.StatusOK {
|
|
t.Fatalf("other owner: %d %s", other.Code, other.Body)
|
|
}
|
|
rowsBefore, _ := e.store.snapshot()
|
|
|
|
refused := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(stale, "fr", journalEntries(nil)...))
|
|
|
|
expectSiteStatusAndBody(t, refused, http.StatusConflict, "languages_changed")
|
|
if rowsAfter, _ := e.store.snapshot(); !reflect.DeepEqual(rowsBefore, rowsAfter) {
|
|
t.Errorf("rows changed")
|
|
}
|
|
retry := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(e.revision(t, "journal"), "fr", journalEntries(nil)...))
|
|
if retry.Code != http.StatusOK {
|
|
t.Errorf("retry: %d %s", retry.Code, retry.Body)
|
|
}
|
|
})
|
|
|
|
t.Run("Sending the same state again is a no-op", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
first := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(e.revision(t, "journal"), "fr", journalEntries(nil)...))
|
|
r2 := decodeLanguagesView(t, first).Revision
|
|
calls := e.store.replaceCalls
|
|
rowsBefore, _ := e.store.snapshot()
|
|
|
|
again := e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(r2, "fr", journalEntries(nil)...))
|
|
|
|
if again.Code != http.StatusOK || decodeLanguagesView(t, again).Revision != r2 {
|
|
t.Fatalf("again: %d %s", again.Code, again.Body)
|
|
}
|
|
if rowsAfter, _ := e.store.snapshot(); e.store.replaceCalls != calls || !reflect.DeepEqual(rowsBefore, rowsAfter) {
|
|
t.Errorf("rows were written again")
|
|
}
|
|
})
|
|
|
|
t.Run("Only an owner can write", func(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
user uint32
|
|
status int
|
|
}{
|
|
{"an anonymous client", 0, http.StatusUnauthorized},
|
|
{"a reader", readerUserID, http.StatusForbidden},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
revision := e.revision(t, "journal")
|
|
rec := e.as(t, c.user, http.MethodPut, "/v1/site/journal/languages", languagesBody(revision, "fr", journalEntries(nil)...))
|
|
if rec.Code != c.status || e.store.replaceCalls != 0 {
|
|
t.Errorf("status %d, writes %d", rec.Code, e.store.replaceCalls)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("Removing a language is decided under the site lock", func(t *testing.T) {
|
|
e := newLocalizationEnv(t)
|
|
e.seedJournal()
|
|
e.owner(t, http.MethodPut, "/v1/site/journal/languages", languagesBody(e.revision(t, "journal"), "en", journalEntries(nil, "en-US")...))
|
|
if !slices.Equal(e.sites.lockedSites, []uint32{journalSiteID}) || e.transactor.runs != 1 {
|
|
t.Errorf("locks %v, transactions %d", e.sites.lockedSites, e.transactor.runs)
|
|
}
|
|
})
|
|
}
|
|
|
|
func socialOnFrench(social string) []string {
|
|
return journalEntries(map[string]string{"fr": entryJSON("fr", true, social)})
|
|
}
|
|
|
|
func countTag(view languagesView, tag string) int {
|
|
total := 0
|
|
for _, entry := range view.Languages {
|
|
if entry.Lang == tag {
|
|
total++
|
|
}
|
|
}
|
|
return total
|
|
}
|
|
|
|
type languageEntryView = struct {
|
|
Lang string `json:"lang"`
|
|
Enabled bool `json:"enabled"`
|
|
IsDefault bool `json:"is_default"`
|
|
VersionCount int `json:"version_count"`
|
|
PublishedCount int `json:"published_count"`
|
|
SocialLocale *string `json:"social_locale"`
|
|
State string `json:"social_locale_state"`
|
|
}
|
|
|
|
func findLanguage(t *testing.T, view languagesView, tag string) languageEntryView {
|
|
t.Helper()
|
|
for _, entry := range view.Languages {
|
|
if entry.Lang == tag {
|
|
return entry
|
|
}
|
|
}
|
|
t.Fatalf("language %s missing from %v", tag, view.tags())
|
|
return languageEntryView{}
|
|
}
|
|
|
|
func TestSiteLanguagesRevision(t *testing.T) {
|
|
base := []localization.Row{{Tag: "en", IsDefault: true, Enabled: true}, {Tag: "fr", Enabled: true}}
|
|
other := func(change func(rows []localization.Row)) string {
|
|
rows := slices.Clone(base)
|
|
change(rows)
|
|
return localization.Revision(rows)
|
|
}
|
|
reference := localization.Revision(base)
|
|
|
|
t.Run("the same rows give the same revision whatever the order", func(t *testing.T) {
|
|
if localization.Revision([]localization.Row{base[1], base[0]}) != reference {
|
|
t.Errorf("order changed the revision")
|
|
}
|
|
})
|
|
t.Run("any change of lang, default, enabled or social_locale gives another one", func(t *testing.T) {
|
|
changes := map[string]func(rows []localization.Row){
|
|
"lang": func(rows []localization.Row) { rows[1].Tag = "de" },
|
|
"default": func(rows []localization.Row) { rows[1].IsDefault = true },
|
|
"enabled": func(rows []localization.Row) { rows[1].Enabled = false },
|
|
"social": func(rows []localization.Row) { rows[1].SocialLocale = localeOf("fr_FR") },
|
|
}
|
|
for name, change := range changes {
|
|
if other(change) == reference {
|
|
t.Errorf("%s did not change the revision", name)
|
|
}
|
|
}
|
|
})
|
|
t.Run("confirmed flags do not change the revision", func(t *testing.T) {
|
|
if other(func(rows []localization.Row) { rows[0].Confirmed = true }) != reference {
|
|
t.Errorf("confirmed changed the revision")
|
|
}
|
|
})
|
|
}
|