diff --git a/internal/modules/misc/handlers_test.go b/internal/modules/misc/handlers_test.go index b997823..e69a142 100644 --- a/internal/modules/misc/handlers_test.go +++ b/internal/modules/misc/handlers_test.go @@ -150,7 +150,7 @@ func TestWheelOfNames_UsageWhenMissingOptions(t *testing.T) { } func TestWheelOfNames_ResultCaptionEscapesHTML(t *testing.T) { - got := wheelResultCaption(``) + got := wheelResultCaption([]string{``}, 0) want := `Result: <Alice & Bob>` if got != want { t.Fatalf("wheelResultCaption() = %q, want %q", got, want) @@ -158,13 +158,25 @@ func TestWheelOfNames_ResultCaptionEscapesHTML(t *testing.T) { } func TestWheelOfNames_ResultCaptionTruncatesLongResult(t *testing.T) { - got := wheelResultCaption(strings.Repeat("a", wheelResultCaptionMaxRunes+1)) + got := wheelResultCaption([]string{strings.Repeat("a", wheelResultCaptionMaxRunes+1)}, 0) want := `Result: ` + strings.Repeat("a", wheelResultCaptionMaxRunes) + `...` if got != want { t.Fatalf("wheelResultCaption() length = %d, want truncated caption length %d", len(got), len(want)) } } +func TestWheelOfNames_ResultCaptionPadsShortWinnerToLongestOption(t *testing.T) { + options := []string{"Bob", "Alexandria"} + got := wheelResultCaption(options, 0) + want := `Result: .......Bob` + if got != want { + t.Fatalf("wheelResultCaption() = %q, want %q", got, want) + } + if longest := wheelResultCaption(options, 1); len([]rune(longest)) != len([]rune(got)) { + t.Fatalf("caption lengths differ: winner %q vs %q", got, longest) + } +} + func TestWheelOfNames_UsesRemoteAPIWhenConfigured(t *testing.T) { var got wheelAPIRequest var gotAuthorization string @@ -206,7 +218,7 @@ func TestWheelOfNames_UsesRemoteAPIWhenConfigured(t *testing.T) { if call.Method != "sendAnimation" { t.Fatalf("method = %q, want sendAnimation", call.Method) } - wantCaption := wheelResultCaption(got.Options[got.WinnerIndex]) + wantCaption := wheelResultCaption(got.Options, got.WinnerIndex) if got := call.Form["caption"]; got != wantCaption { t.Fatalf("caption = %q, want %q", got, wantCaption) } diff --git a/internal/modules/misc/wheelofnames_command.go b/internal/modules/misc/wheelofnames_command.go index acd096d..f49f166 100644 --- a/internal/modules/misc/wheelofnames_command.go +++ b/internal/modules/misc/wheelofnames_command.go @@ -5,6 +5,7 @@ import ( "context" "errors" "html" + "strings" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" @@ -51,7 +52,7 @@ func wheelOfNamesCommand() modules.Command { Duration: animation.Duration, Width: animation.Width, Height: animation.Height, - Caption: wheelResultCaption(options[winner]), + Caption: wheelResultCaption(options, winner), ParseMode: models.ParseModeHTML, }) if err != nil { @@ -65,9 +66,22 @@ func wheelOfNamesCommand() modules.Command { const wheelUsage = "Usage: /wheelofnames " -func wheelResultCaption(result string) string { - result = truncateWheelResultCaption(result) - return `Result: ` + html.EscapeString(result) + `` +func wheelResultCaption(options []string, winner int) string { + result := truncateWheelResultCaption(options[winner]) + padding := wheelCaptionPadding(options, len([]rune(result))) + return `Result: ` + html.EscapeString(padding+result) + `` +} + +// wheelCaptionPadding returns leading dots so every option renders a +// spoiler of equal length; otherwise the spoiler width reveals the winner. +func wheelCaptionPadding(options []string, resultRunes int) string { + longest := resultRunes + for _, option := range options { + if n := len([]rune(truncateWheelResultCaption(option))); n > longest { + longest = n + } + } + return strings.Repeat(".", longest-resultRunes) } func truncateWheelResultCaption(result string) string {