Add full shell, replaceable Omics adapter and bilingual interaction

Implement approved specification #32 and tickets #33-#37. Keep host authentication server-verified and pin session interaction language. Compile scoped base selectors for browser compatibility and retain full gutters during CSS pruning.
This commit is contained in:
Codex
2026-09-13 14:26:39 +02:00
parent 2d1b714ebe
commit d8a29bfbdd
207 changed files with 8570 additions and 2164 deletions
@@ -0,0 +1,78 @@
package setup
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/aritmolab/thothii/tools/tht/internal/config"
)
func TestEnsureFilesProjectsShellAnswersThroughInstallationLoad(t *testing.T) {
for _, test := range []struct {
name string
answers Answers
want config.Shell
}{
{"defaults", Answers{}, config.Shell{Mode: "embedded", DefaultLocale: "en", Adapter: "omics-portal"}},
{"full", Answers{ShellMode: "full"}, config.Shell{Mode: "full", DefaultLocale: "en"}},
{"locale without UI catalog", Answers{ShellMode: "full", ShellDefaultLocale: "fr-CA"}, config.Shell{Mode: "full", DefaultLocale: "fr-CA"}},
{"embedded Italian", Answers{ShellMode: "embedded", ShellDefaultLocale: "it", ShellAdapter: "omics-portal"}, config.Shell{Mode: "embedded", DefaultLocale: "it", Adapter: "omics-portal"}},
} {
t.Run(test.name, func(t *testing.T) {
root := newProject(t, "shell setup")
setNonInteractiveAnswers(t, newExternalSecrets(t, root))
for _, key := range []string{"THT_SETUP_SHELL_MODE", "THT_SETUP_SHELL_DEFAULT_LOCALE", "THT_SETUP_SHELL_ADAPTER"} {
t.Setenv(key, "")
}
request := Request{ProjectRoot: root, InstallationID: "shell", Profile: "local", NonInteractive: true, Answers: test.answers}
result, err := EnsureFiles(request, strings.NewReader(""), ioDiscard{})
if err != nil {
t.Fatal(err)
}
installation, err := config.Load(result.DescriptorPath)
if err != nil || installation.Shell != test.want {
t.Fatalf("Load() shell = %#v, %v, want %#v", installation.Shell, err, test.want)
}
if repeated, err := EnsureFiles(request, strings.NewReader(""), ioDiscard{}); err != nil || len(repeated.Created) != 0 {
t.Fatalf("repeated setup = %#v, %v", repeated, err)
}
})
}
}
func TestEnsureFilesAcceptsShellEnvironmentAndExplicitPrecedence(t *testing.T) {
root := newProject(t, "shell environment")
setNonInteractiveAnswers(t, newExternalSecrets(t, root))
t.Setenv("THT_SETUP_SHELL_MODE", "embedded")
t.Setenv("THT_SETUP_SHELL_DEFAULT_LOCALE", "it")
t.Setenv("THT_SETUP_SHELL_ADAPTER", "omics-portal")
result, err := EnsureFiles(Request{
ProjectRoot: root, InstallationID: "shell", Profile: "local", NonInteractive: true,
Answers: Answers{ShellMode: "full"},
}, strings.NewReader(""), ioDiscard{})
if err != nil {
t.Fatal(err)
}
installation, err := config.Load(result.DescriptorPath)
if err != nil || installation.Shell != (config.Shell{Mode: "full", DefaultLocale: "it"}) {
t.Fatalf("Load() shell = %#v, %v", installation.Shell, err)
}
}
func TestEnsureFilesRejectsInvalidShellBeforeWritingInstallation(t *testing.T) {
for _, answers := range []Answers{{ShellMode: "fullscreen"}, {ShellDefaultLocale: "de_DE"}, {ShellAdapter: "unknown"}} {
root := newProject(t, "invalid shell")
setNonInteractiveAnswers(t, newExternalSecrets(t, root))
_, err := EnsureFiles(Request{
ProjectRoot: root, InstallationID: "shell", Profile: "local", NonInteractive: true, Answers: answers,
}, strings.NewReader(""), ioDiscard{})
if err == nil || !strings.Contains(err.Error(), "shell.") {
t.Fatalf("EnsureFiles() error = %v", err)
}
if _, err := os.Stat(filepath.Join(root, "deploy", "shell")); !os.IsNotExist(err) {
t.Fatalf("invalid shell created installation directory: %v", err)
}
}
}