294 lines
8.4 KiB
Go
294 lines
8.4 KiB
Go
// SPDX-Licence-Identifier: EUPL-1.2
|
|
|
|
package html
|
|
|
|
import (
|
|
"testing"
|
|
|
|
i18n "dappco.re/go/core/i18n"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type localeTranslator struct {
|
|
language string
|
|
}
|
|
|
|
func (t *localeTranslator) T(key string, args ...any) string {
|
|
if key == "prompt.yes" && t.language == "fr" {
|
|
return "o"
|
|
}
|
|
if key == "prompt.yes" && t.language == "en" {
|
|
return "y"
|
|
}
|
|
return key
|
|
}
|
|
|
|
func (t *localeTranslator) SetLanguage(language string) error {
|
|
t.language = language
|
|
return nil
|
|
}
|
|
|
|
func TestContext_NewContextWithService_AppliesLocale(t *testing.T) {
|
|
svc := &localeTranslator{}
|
|
ctx := NewContextWithService(svc, "fr-FR")
|
|
|
|
if svc.language != "fr" {
|
|
t.Fatalf("NewContextWithService should apply locale to translator, got %q", svc.language)
|
|
}
|
|
|
|
if got := Text("prompt.yes").Render(ctx); got != "o" {
|
|
t.Fatalf("NewContextWithService locale translation = %q, want %q", got, "o")
|
|
}
|
|
}
|
|
|
|
func TestContext_NewContext_AppliesLocaleToDefaultService(t *testing.T) {
|
|
ctx := NewContext("fr-FR")
|
|
|
|
if got := Text("prompt.yes").Render(ctx); got != "o" {
|
|
t.Fatalf("NewContext(locale) translation = %q, want %q", got, "o")
|
|
}
|
|
}
|
|
|
|
func TestContext_NewContextWithService_UsesLocale(t *testing.T) {
|
|
svc := &localeTranslator{}
|
|
ctx := NewContextWithService(svc, "en-GB")
|
|
|
|
if svc.language != "en" {
|
|
t.Fatalf("NewContextWithService should apply locale to translator, got %q", svc.language)
|
|
}
|
|
|
|
if got := Text("prompt.yes").Render(ctx); got != "y" {
|
|
t.Fatalf("NewContextWithService translation = %q, want %q", got, "y")
|
|
}
|
|
}
|
|
|
|
func TestContext_SetLocale_ReappliesToTranslator(t *testing.T) {
|
|
svc := &localeTranslator{}
|
|
ctx := NewContextWithService(svc, "en-GB")
|
|
|
|
ctx.SetLocale("fr-FR")
|
|
|
|
if ctx.Locale != "fr-FR" {
|
|
t.Fatalf("SetLocale should update context locale, got %q", ctx.Locale)
|
|
}
|
|
if svc.language != "fr" {
|
|
t.Fatalf("SetLocale should reapply locale to translator, got %q", svc.language)
|
|
}
|
|
if got := Text("prompt.yes").Render(ctx); got != "o" {
|
|
t.Fatalf("SetLocale translation = %q, want %q", got, "o")
|
|
}
|
|
}
|
|
|
|
func TestContext_SetService_ReappliesCurrentLocale(t *testing.T) {
|
|
ctx := NewContext("fr-FR")
|
|
svc := &localeTranslator{}
|
|
|
|
ctx.SetService(svc)
|
|
|
|
if ctx.service != svc {
|
|
t.Fatalf("SetService should replace the active translator")
|
|
}
|
|
if svc.language != "fr" {
|
|
t.Fatalf("SetService should apply the existing locale to the new translator, got %q", svc.language)
|
|
}
|
|
if got := Text("prompt.yes").Render(ctx); got != "o" {
|
|
t.Fatalf("SetService translation = %q, want %q", got, "o")
|
|
}
|
|
}
|
|
|
|
func TestContext_SetIdentity_UpdatesIdentity(t *testing.T) {
|
|
ctx := NewContext()
|
|
|
|
if got := ctx.SetIdentity("user-123"); got != ctx {
|
|
t.Fatalf("SetIdentity should return the same context")
|
|
}
|
|
if ctx.Identity != "user-123" {
|
|
t.Fatalf("SetIdentity should update context identity, got %q", ctx.Identity)
|
|
}
|
|
if ctx.Data == nil {
|
|
t.Fatal("SetIdentity should preserve initialised Data map")
|
|
}
|
|
}
|
|
|
|
func TestContext_SetData_StoresValue(t *testing.T) {
|
|
ctx := NewContext()
|
|
|
|
if got := ctx.SetData("theme", "dark"); got != ctx {
|
|
t.Fatalf("SetData should return the same context")
|
|
}
|
|
if got := ctx.Data["theme"]; got != "dark" {
|
|
t.Fatalf("SetData should store the requested value, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestContext_SetData_InitialisesNilMap(t *testing.T) {
|
|
ctx := &Context{}
|
|
|
|
ctx.SetData("theme", "light")
|
|
|
|
if ctx.Data == nil {
|
|
t.Fatal("SetData should initialise the Data map on demand")
|
|
}
|
|
if got := ctx.Data["theme"]; got != "light" {
|
|
t.Fatalf("SetData should store the requested value in a nil map context, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestContext_CloneCopiesDataWithoutSharingMap(t *testing.T) {
|
|
svc := &localeTranslator{}
|
|
ctx := NewContextWithService(svc, "en-GB")
|
|
ctx.SetIdentity("user-123")
|
|
ctx.SetData("theme", "dark")
|
|
|
|
clone := ctx.Clone()
|
|
|
|
if clone == ctx {
|
|
t.Fatal("Clone should return a distinct context instance")
|
|
}
|
|
if clone.service != ctx.service {
|
|
t.Fatal("Clone should preserve the active translator")
|
|
}
|
|
if clone.Locale != ctx.Locale {
|
|
t.Fatalf("Clone should preserve locale, got %q want %q", clone.Locale, ctx.Locale)
|
|
}
|
|
if clone.Identity != ctx.Identity {
|
|
t.Fatalf("Clone should preserve identity, got %q want %q", clone.Identity, ctx.Identity)
|
|
}
|
|
|
|
clone.SetData("theme", "light")
|
|
if got := ctx.Data["theme"]; got != "dark" {
|
|
t.Fatalf("Clone should not share Data map with original, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestContext_WithDataReturnsClonedContext(t *testing.T) {
|
|
ctx := NewContext()
|
|
ctx.SetData("theme", "dark")
|
|
|
|
next := ctx.WithData("locale", "fr-FR")
|
|
|
|
if next == ctx {
|
|
t.Fatal("WithData should return a cloned context")
|
|
}
|
|
if got := ctx.Data["locale"]; got != nil {
|
|
t.Fatalf("WithData should not mutate the original context, got %v", got)
|
|
}
|
|
if got := next.Data["locale"]; got != "fr-FR" {
|
|
t.Fatalf("WithData should set the requested value on the clone, got %v", got)
|
|
}
|
|
if got := next.Data["theme"]; got != "dark" {
|
|
t.Fatalf("WithData should preserve existing data on the clone, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestContext_WithIdentityReturnsClonedContext(t *testing.T) {
|
|
ctx := NewContext()
|
|
ctx.SetIdentity("user-001")
|
|
ctx.SetData("theme", "dark")
|
|
|
|
next := ctx.WithIdentity("user-123")
|
|
|
|
if next == ctx {
|
|
t.Fatal("WithIdentity should return a cloned context")
|
|
}
|
|
if got := ctx.Identity; got != "user-001" {
|
|
t.Fatalf("WithIdentity should not mutate the original context, got %q", got)
|
|
}
|
|
if got := next.Identity; got != "user-123" {
|
|
t.Fatalf("WithIdentity should set the requested identity on the clone, got %q", got)
|
|
}
|
|
if got := next.Data["theme"]; got != "dark" {
|
|
t.Fatalf("WithIdentity should preserve existing data on the clone, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestContext_WithLocaleReturnsClonedContext(t *testing.T) {
|
|
svc := &localeTranslator{}
|
|
ctx := NewContextWithService(svc, "en-GB")
|
|
ctx.SetIdentity("user-001")
|
|
ctx.SetData("theme", "dark")
|
|
|
|
next := ctx.WithLocale("fr-FR")
|
|
|
|
if next == ctx {
|
|
t.Fatal("WithLocale should return a cloned context")
|
|
}
|
|
if got := ctx.Locale; got != "en-GB" {
|
|
t.Fatalf("WithLocale should not mutate the original context locale, got %q", got)
|
|
}
|
|
if got := next.Locale; got != "fr-FR" {
|
|
t.Fatalf("WithLocale should set the requested locale on the clone, got %q", got)
|
|
}
|
|
if got := next.service; got != ctx.service {
|
|
t.Fatal("WithLocale should preserve the active translator on the clone")
|
|
}
|
|
if svc.language != "fr" {
|
|
t.Fatalf("WithLocale should reapply locale to the cloned service, got %q", svc.language)
|
|
}
|
|
if got := next.Data["theme"]; got != "dark" {
|
|
t.Fatalf("WithLocale should preserve existing data on the clone, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestContext_WithServiceReturnsClonedContext(t *testing.T) {
|
|
ctx := NewContext("fr-FR")
|
|
ctx.SetIdentity("user-001")
|
|
ctx.SetData("theme", "dark")
|
|
|
|
svc := &localeTranslator{}
|
|
next := ctx.WithService(svc)
|
|
|
|
if next == ctx {
|
|
t.Fatal("WithService should return a cloned context")
|
|
}
|
|
if got := ctx.service; got == svc {
|
|
t.Fatal("WithService should not mutate the original context service")
|
|
}
|
|
if got := next.service; got != svc {
|
|
t.Fatalf("WithService should set the requested service on the clone, got %v", got)
|
|
}
|
|
if svc.language != "fr" {
|
|
t.Fatalf("WithService should apply the existing locale to the new translator, got %q", svc.language)
|
|
}
|
|
if got := next.Data["theme"]; got != "dark" {
|
|
t.Fatalf("WithService should preserve existing data on the clone, got %v", got)
|
|
}
|
|
if got := next.Locale; got != "fr-FR" {
|
|
t.Fatalf("WithService should preserve the locale on the clone, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestContext_Setters_NilReceiver(t *testing.T) {
|
|
var ctx *Context
|
|
|
|
if got := ctx.SetIdentity("user-123"); got != nil {
|
|
t.Fatalf("nil Context.SetIdentity should return nil, got %v", got)
|
|
}
|
|
if got := ctx.SetData("theme", "dark"); got != nil {
|
|
t.Fatalf("nil Context.SetData should return nil, got %v", got)
|
|
}
|
|
if got := ctx.SetLocale("en-GB"); got != nil {
|
|
t.Fatalf("nil Context.SetLocale should return nil, got %v", got)
|
|
}
|
|
if got := ctx.SetService(&localeTranslator{}); got != nil {
|
|
t.Fatalf("nil Context.SetService should return nil, got %v", got)
|
|
}
|
|
if got := ctx.WithLocale("en-GB"); got != nil {
|
|
t.Fatalf("nil Context.WithLocale should return nil, got %v", got)
|
|
}
|
|
if got := ctx.WithService(&localeTranslator{}); got != nil {
|
|
t.Fatalf("nil Context.WithService should return nil, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestText_RenderFallsBackToDefaultTranslator(t *testing.T) {
|
|
svc, _ := i18n.New()
|
|
i18n.SetDefault(svc)
|
|
require.NoError(t, svc.SetLanguage("fr"))
|
|
|
|
ctx := &Context{}
|
|
|
|
if got := Text("prompt.yes").Render(ctx); got != "o" {
|
|
t.Fatalf("Text() fallback translation = %q, want %q", got, "o")
|
|
}
|
|
}
|