From 10ec9d1d6eed6c8840f0ced7ec127cfbdfb4d139 Mon Sep 17 00:00:00 2001 From: Esa Kataja Date: Sat, 5 Sep 2026 12:46:08 +0300 Subject: [PATCH] Move to Go 1.27, and fix initials for non-ASCII names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initials() capped the loop with len(out) == 2, which counts bytes: a name starting with Ä, Ö or Å filled the budget on its own and returned a single letter. Count the initials taken instead. go fix also wanted a strings.Builder here, but that allocates a string per iteration to measure a two-character result. Took its SplitSeq suggestion in lyrics.go, which drops an intermediate slice. --- Dockerfile | 2 +- auth.go | 5 +++-- auth_test.go | 14 ++++++++++++++ go.mod | 2 +- lyrics.go | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index cb35ab2..e18db23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.26-alpine AS build +FROM golang:1.27-alpine AS build # CalVer, injected at build so no file needs bumping by hand: docker build --build-arg VERSION=… ARG VERSION=dev WORKDIR /src diff --git a/auth.go b/auth.go index 23b841b..1a8a417 100644 --- a/auth.go +++ b/auth.go @@ -35,10 +35,11 @@ type member struct { // Initials for the avatar circle: no default image on disk, no identicon generator. func (m *member) Initials() string { - out := "" + out, n := "", 0 for _, f := range strings.Fields(m.Name) { out += strings.ToUpper(string([]rune(f)[0])) - if len(out) == 2 { + // ponytail: count runes taken, not bytes — "Ä" is 2 bytes and used to end the loop early. + if n++; n == 2 { break } } diff --git a/auth_test.go b/auth_test.go index f601fc4..eb3a13d 100644 --- a/auth_test.go +++ b/auth_test.go @@ -230,3 +230,17 @@ func TestBanDropsSessionsAndBlocksLogin(t *testing.T) { t.Fatalf("login after unban: status = %d, want 303", w.Code) } } + +func TestInitials(t *testing.T) { + for name, want := range map[string]string{ + "Esa Kataja": "EK", + "Ärväs Öhman": "ÄÖ", // multi-byte initials must not end the loop early + "Åke": "Å", + "": "", + "a b c": "AB", + } { + if got := (&member{Name: name}).Initials(); got != want { + t.Errorf("Initials(%q) = %q, want %q", name, got, want) + } + } +} diff --git a/go.mod b/go.mod index 8e2f015..1cdf608 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module git.kessinen.com/kessinen/levyraati26-go -go 1.25.0 +go 1.27.0 require ( golang.org/x/crypto v0.32.0 diff --git a/lyrics.go b/lyrics.go index 1061c94..a769fc3 100644 --- a/lyrics.go +++ b/lyrics.go @@ -67,7 +67,7 @@ func parseLRC(s string) []lyricLine { return nil } var out []lyricLine - for _, raw := range strings.Split(s, "\n") { + for raw := range strings.SplitSeq(s, "\n") { stamps := lrcOne.FindAllStringSubmatch(raw, -1) if len(stamps) == 0 { continue