package web import ( "html" "io" "log" "strings" "testing" "time" "gitea.dooplex.hu/admin/felhom-controller/internal/backup" "gitea.dooplex.hu/admin/felhom-controller/internal/stacks" "gitea.dooplex.hu/admin/felhom-controller/internal/util" ) // R-606 (v0.264.0) — every sentence of the update path reaches the page in the READER's language, on // BOTH pages that carry it (the app page and the apps list): the phase label, the update error and the // hold sentence. Asserted both ways — the English present AND the Hungarian gone — because a page // carrying both would pass a presence check (the composed-sentence class, R-573/R-590/R-596/R-598). // // COMPANION RED-PROOF (REPORT.md): make localeFuncs' updateErrorText return .UpdateError — the English // page carries the Hungarian sentence and this test fails. func TestR606_UpdateSentencesFollowTheReader(t *testing.T) { s := i18nTestServer(t) b := backup.NewManager(s.cfg, s.settings, log.New(io.Discard, "", 0)) s.backupMgr = b at := time.Date(2026, 9, 23, 8, 0, 0, 0, time.UTC) if err := b.HoldAfterFailedUpdateHolding("kimai", at, at.Add(-6*time.Hour), backup.UpdateTierLocal, b.UpdateCopyHolds("kimai", backup.UpdateTierLocal), ""); err != nil { t.Fatal(err) } _, holdHU := b.RestoreHoldForLang("kimai", "hu") errStack := i18nStack("gokapi", "Go Kapi", stacks.StateRunning, true) errStack.UpdateErrorKey, errStack.UpdateErrorArgs = "update.error.pull_failed", nil errStack.UpdateError = stacks.MsgUpdatePullFailed upd := i18nStack("romm", "Rom Manager", stacks.StateRunning, true) upd.Updating, upd.UpdatePhase, upd.UpdatePhaseLabel = true, stacks.UpdatePhaseCopying, stacks.UpdatePhaseLabel(stacks.UpdatePhaseCopying) held := i18nStack("kimai", "Kimai Time", stacks.StateStopped, true) held.HoldReason = holdHU pages := []i18nCase{ {"r606_list", "stacks", func() map[string]interface{} { d := i18nLayoutData("stacks", "Alkalmazások") d["Stacks"] = []stacks.Stack{errStack, upd, held} for _, k := range []string{"Subdomains", "MissingStorage", "NetworkStubs", "NetworkWarnings", "StorageLabels"} { d[k] = map[string]string{} } return d }}, {"r606_app_error", "app_info", func() map[string]interface{} { d := i18nLayoutData("stacks", "Go Kapi") st := errStack d["Stack"], d["Meta"], d["AppInfo"] = &st, st.Meta, st.Meta.AppInfo return d }}, {"r606_app_held", "app_info", func() map[string]interface{} { d := i18nLayoutData("stacks", "Kimai") st := held d["Stack"], d["Meta"], d["AppInfo"] = &st, st.Meta, st.Meta.AppInfo return d }}, {"r606_app_updating", "app_info", func() map[string]interface{} { d := i18nLayoutData("stacks", "RomM") st := upd d["Stack"], d["Meta"], d["AppInfo"] = &st, st.Meta, st.Meta.AppInfo return d }}, } type want struct{ en, hu string } sentences := map[string][]want{ "r606_list": { {util.Text("en", "update.error.pull_failed"), stacks.MsgUpdatePullFailed}, {"Copying the data before the update…", "Az adatok másolása a frissítés előtt…"}, {"own drive", "saját meghajtó"}, {"holds the settings, the database and the data volumes", "a beállításokat, az adatbázist és az adatköteteket tartalmazza"}, }, "r606_app_error": {{util.Text("en", "update.error.pull_failed"), stacks.MsgUpdatePullFailed}}, "r606_app_held": {{"The update of kimai at 2026-09-23 10:00 did not succeed", "A(z) kimai frissítése 2026-09-23 10:00-kor nem sikerült"}}, "r606_app_updating": {{"Copying the data before the update…", "Az adatok másolása a frissítés előtt…"}}, } for _, c := range pages { en := html.UnescapeString(renderI18nCase(t, s, "en", c)) hu := html.UnescapeString(renderI18nCase(t, s, "hu", c)) for _, w := range sentences[c.name] { if !strings.Contains(en, w.en) { t.Errorf("%s: the English page lacks %q", c.name, w.en) } if strings.Contains(en, w.hu) { t.Errorf("%s: the Hungarian %q must be GONE from the English page", c.name, w.hu) } if !strings.Contains(hu, w.hu) { t.Errorf("%s: the Hungarian page lacks %q", c.name, w.hu) } } } }