owpengram-server/internal/domain/login_code_delivery_test.go
2026-09-01 14:40:06 +03:00

132 lines
5.6 KiB
Go

package domain
import (
"errors"
"strings"
"testing"
)
func TestValidateLoginCodeMessageTemplate(t *testing.T) {
if err := ValidateLoginCodeMessageTemplate("Your code is {{code}}."); err != nil {
t.Fatalf("exactly one {{code}} should be valid, got %v", err)
}
if err := ValidateLoginCodeMessageTemplate("No placeholder here."); !errors.Is(err, ErrLoginCodeMessageTemplateMissingCode) {
t.Fatalf("zero occurrences should be rejected, got %v", err)
}
if err := ValidateLoginCodeMessageTemplate("{{code}} and again {{code}}."); !errors.Is(err, ErrLoginCodeMessageTemplateMissingCode) {
t.Fatalf("two occurrences should be rejected, got %v", err)
}
if err := ValidateLoginCodeMessageTemplate(""); !errors.Is(err, ErrLoginCodeMessageTemplateMissingCode) {
t.Fatalf("empty template should be rejected, got %v", err)
}
}
func TestResolveLoginCodeMessageTemplatePrecedence(t *testing.T) {
const panel = "panel override {{code}}"
const env = "env default {{code}}"
if got := ResolveLoginCodeMessageTemplate(panel, env); got != panel {
t.Fatalf("panel override should win, got %q", got)
}
if got := ResolveLoginCodeMessageTemplate("", env); got != env {
t.Fatalf("env default should win when panel unset, got %q", got)
}
if got := ResolveLoginCodeMessageTemplate(" ", env); got != env {
t.Fatalf("whitespace-only panel override should be treated as unset, got %q", got)
}
if got := ResolveLoginCodeMessageTemplate("", ""); got != DefaultLoginCodeMessageTemplate {
t.Fatalf("built-in default should be the final fallback, got %q", got)
}
}
func TestOfficialLoginCodeMessageDynamicEntityOffset(t *testing.T) {
SetOfficialSystemUserDisplayName("")
defer SetOfficialSystemUserDisplayName("")
// {{code}} is nowhere near a fixed prefix here -- it sits at the end of
// a sentence, after other text -- proving the entity offset is computed
// from where the placeholder actually landed, not assumed from a
// hardcoded "Login code: " prefix the way the old %s-based
// implementation did.
template := "Please do not share your one-time code, which is: {{code}} -- thanks!"
msg, err := OfficialLoginCodeMessage(7, template, "998877", 1700000000)
if err != nil {
t.Fatalf("OfficialLoginCodeMessage: %v", err)
}
wantBody := "Please do not share your one-time code, which is: 998877 -- thanks!"
if msg.Body != wantBody {
t.Fatalf("body = %q, want %q", msg.Body, wantBody)
}
if len(msg.Entities) != 1 {
t.Fatalf("expected exactly one entity, got %d: %+v", len(msg.Entities), msg.Entities)
}
entity := msg.Entities[0]
if entity.Type != MessageEntityBold {
t.Fatalf("expected bold entity, got %v", entity.Type)
}
wantOffset := automaticEntityUTF16Length("Please do not share your one-time code, which is: ")
if entity.Offset != wantOffset {
t.Fatalf("offset = %d, want %d", entity.Offset, wantOffset)
}
if entity.Length != automaticEntityUTF16Length("998877") {
t.Fatalf("length = %d, want %d", entity.Length, automaticEntityUTF16Length("998877"))
}
}
func TestOfficialLoginCodeMessageOffsetShiftsWithServerNameSubstitution(t *testing.T) {
SetOfficialSystemUserDisplayName("A Much Longer Custom Server Name")
defer SetOfficialSystemUserDisplayName("")
// {{server_name}} is substituted BEFORE {{code}}'s position is located,
// so a longer server name shifts the code's offset. If the offset math
// were still relying on a fixed/original position (e.g. computed
// against the raw un-substituted template), this would land on the
// wrong text.
template := "Server {{server_name}} says your code is {{code}}."
msg, err := OfficialLoginCodeMessage(7, template, "42", 1)
if err != nil {
t.Fatalf("OfficialLoginCodeMessage: %v", err)
}
wantBody := "Server A Much Longer Custom Server Name says your code is 42."
if msg.Body != wantBody {
t.Fatalf("body = %q, want %q", msg.Body, wantBody)
}
wantOffset := automaticEntityUTF16Length("Server A Much Longer Custom Server Name says your code is ")
if len(msg.Entities) != 1 || msg.Entities[0].Offset != wantOffset {
t.Fatalf("entities = %+v, want single bold entity at offset %d", msg.Entities, wantOffset)
}
}
func TestOfficialLoginCodeMessageFallsBackWhenTemplateInvalid(t *testing.T) {
SetOfficialSystemUserDisplayName("")
defer SetOfficialSystemUserDisplayName("")
// Defense in depth: a template that somehow reaches here without
// {{code}} (or with it more than once) must never ship a message
// silently missing the actual OTP -- it falls back to the compiled-in
// default instead.
for _, template := range []string{"", "no placeholder", "{{code}} twice {{code}}"} {
msg, err := OfficialLoginCodeMessage(7, template, "13579", 1)
if err != nil {
t.Fatalf("template %q: OfficialLoginCodeMessage: %v", template, err)
}
if !strings.Contains(msg.Body, "13579") {
t.Fatalf("template %q: fallback body missing code: %q", template, msg.Body)
}
if len(msg.Entities) != 1 || msg.Entities[0].Length != automaticEntityUTF16Length("13579") {
t.Fatalf("template %q: unexpected entities: %+v", template, msg.Entities)
}
}
}
func TestOfficialLoginCodeMessageValidation(t *testing.T) {
if _, err := OfficialLoginCodeMessage(0, "{{code}}", "12345", 1); !errors.Is(err, ErrLoginCodeDeliveryInvalid) {
t.Fatalf("expected invalid user id to be rejected, got %v", err)
}
if _, err := OfficialLoginCodeMessage(7, "{{code}}", "", 1); !errors.Is(err, ErrLoginCodeDeliveryInvalid) {
t.Fatalf("expected empty code to be rejected, got %v", err)
}
if _, err := OfficialLoginCodeMessage(OfficialSystemUserID, "{{code}}", "12345", 1); !errors.Is(err, ErrLoginCodeDeliveryInvalid) {
t.Fatalf("expected system user id to be rejected, got %v", err)
}
}