205 lines
7.5 KiB
Go
205 lines
7.5 KiB
Go
package templates
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"galaxy/mail/internal/domain/common"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewCatalogBuildsImmutableRegistry(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "subject.tmpl"), "Your login code")
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "text.tmpl"), "Code: {{.code}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "fr-fr", "subject.tmpl"), "Tour {{.turn_number}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "fr-fr", "text.tmpl"), "Bonjour {{with .player}}{{.name}}{{end}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "fr-fr", "html.tmpl"), "<p>{{.player.name}}</p>")
|
|
|
|
catalog, err := NewCatalog(rootDir)
|
|
require.NoError(t, err)
|
|
require.Equal(t, filepath.Clean(rootDir), catalog.RootDir())
|
|
|
|
locale, err := common.ParseLocale("fr-FR")
|
|
require.NoError(t, err)
|
|
resolved, err := catalog.Lookup(common.TemplateID("game.turn.ready"), locale)
|
|
require.NoError(t, err)
|
|
require.False(t, resolved.LocaleFallbackUsed())
|
|
require.Equal(t, common.Locale("fr-FR"), resolved.ResolvedLocale())
|
|
require.Equal(t, []string{"player", "player.name", "turn_number"}, resolved.RequiredVariablePaths())
|
|
|
|
subject, err := resolved.ExecuteSubject(map[string]any{
|
|
"turn_number": 54,
|
|
"player": map[string]any{
|
|
"name": "Pilot",
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Tour 54", subject)
|
|
|
|
textBody, err := resolved.ExecuteText(map[string]any{
|
|
"player": map[string]any{
|
|
"name": "Pilot",
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Bonjour Pilot", textBody)
|
|
|
|
htmlBody, ok, err := resolved.ExecuteHTML(map[string]any{
|
|
"player": map[string]any{
|
|
"name": "Pilot",
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
require.True(t, ok)
|
|
require.Equal(t, "<p>Pilot</p>", htmlBody)
|
|
}
|
|
|
|
func TestCatalogLookupFallsBackToEnglish(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "subject.tmpl"), "Your login code")
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "text.tmpl"), "Code: {{.code}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "subject.tmpl"), "Turn {{.turn_number}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "text.tmpl"), "Hello {{.player.name}}")
|
|
|
|
catalog, err := NewCatalog(rootDir)
|
|
require.NoError(t, err)
|
|
|
|
locale, err := common.ParseLocale("fr-FR")
|
|
require.NoError(t, err)
|
|
resolved, err := catalog.Lookup(common.TemplateID("game.turn.ready"), locale)
|
|
require.NoError(t, err)
|
|
require.True(t, resolved.LocaleFallbackUsed())
|
|
require.Equal(t, common.Locale("en"), resolved.ResolvedLocale())
|
|
}
|
|
|
|
func TestCatalogLookupRejectsMissingEnglishFallback(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "subject.tmpl"), "Your login code")
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "text.tmpl"), "Code: {{.code}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "fr-FR", "subject.tmpl"), "Tour {{.turn_number}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "fr-FR", "text.tmpl"), "Bonjour {{.player.name}}")
|
|
|
|
catalog, err := NewCatalog(rootDir)
|
|
require.NoError(t, err)
|
|
|
|
locale, err := common.ParseLocale("de-DE")
|
|
require.NoError(t, err)
|
|
_, err = catalog.Lookup(common.TemplateID("game.turn.ready"), locale)
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, ErrFallbackMissing))
|
|
}
|
|
|
|
func TestCatalogLookupRejectsUnknownTemplateFamily(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "subject.tmpl"), "Your login code")
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "text.tmpl"), "Code: {{.code}}")
|
|
|
|
catalog, err := NewCatalog(rootDir)
|
|
require.NoError(t, err)
|
|
|
|
locale, err := common.ParseLocale("en")
|
|
require.NoError(t, err)
|
|
_, err = catalog.Lookup(common.TemplateID("game.turn.ready"), locale)
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, ErrTemplateNotFound))
|
|
}
|
|
|
|
func TestCatalogAllowsTemplateWithoutHTML(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "subject.tmpl"), "Your login code")
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "text.tmpl"), "Code: {{.code}}")
|
|
|
|
catalog, err := NewCatalog(rootDir)
|
|
require.NoError(t, err)
|
|
|
|
locale, err := common.ParseLocale("en")
|
|
require.NoError(t, err)
|
|
resolved, err := catalog.Lookup(common.TemplateID("auth.login_code"), locale)
|
|
require.NoError(t, err)
|
|
|
|
htmlBody, ok, err := resolved.ExecuteHTML(map[string]any{"code": "123456"})
|
|
require.NoError(t, err)
|
|
require.False(t, ok)
|
|
require.Empty(t, htmlBody)
|
|
}
|
|
|
|
func TestCatalogVersionIsDeterministic(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "subject.tmpl"), "Your login code")
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "text.tmpl"), "Code: {{.code}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "subject.tmpl"), "Turn {{.turn_number}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "text.tmpl"), "Hello {{.player.name}}")
|
|
|
|
firstCatalog, err := NewCatalog(rootDir)
|
|
require.NoError(t, err)
|
|
secondCatalog, err := NewCatalog(rootDir)
|
|
require.NoError(t, err)
|
|
|
|
locale, err := common.ParseLocale("en")
|
|
require.NoError(t, err)
|
|
firstResolved, err := firstCatalog.Lookup(common.TemplateID("game.turn.ready"), locale)
|
|
require.NoError(t, err)
|
|
secondResolved, err := secondCatalog.Lookup(common.TemplateID("game.turn.ready"), locale)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, firstResolved.Template().Version, secondResolved.Template().Version)
|
|
}
|
|
|
|
func TestNewCatalogRejectsMissingDirectory(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := NewCatalog(filepath.Join(t.TempDir(), "missing"))
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "stat root dir")
|
|
}
|
|
|
|
func TestNewCatalogRejectsMissingRequiredStartupTemplate(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "subject.tmpl"), "Turn {{.turn_number}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "text.tmpl"), "Hello {{.player.name}}")
|
|
|
|
_, err := NewCatalog(rootDir)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), `required template "auth.login_code" locale "en" is missing`)
|
|
}
|
|
|
|
func TestNewCatalogRejectsBrokenTemplateParse(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rootDir := t.TempDir()
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "subject.tmpl"), "Your login code")
|
|
writeTemplateFile(t, rootDir, filepath.Join("auth.login_code", "en", "text.tmpl"), "Code: {{.code}}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "subject.tmpl"), "{{if .turn_number}")
|
|
writeTemplateFile(t, rootDir, filepath.Join("game.turn.ready", "en", "text.tmpl"), "Hello {{.player.name}}")
|
|
|
|
_, err := NewCatalog(rootDir)
|
|
require.Error(t, err)
|
|
require.True(t, errors.Is(err, ErrTemplateParseFailed))
|
|
}
|
|
|
|
func writeTemplateFile(t *testing.T, rootDir string, relativePath string, contents string) {
|
|
t.Helper()
|
|
|
|
absolutePath := filepath.Join(rootDir, relativePath)
|
|
require.NoError(t, os.MkdirAll(filepath.Dir(absolutePath), 0o755))
|
|
require.NoError(t, os.WriteFile(absolutePath, []byte(contents), 0o644))
|
|
}
|