108 lines
4.1 KiB
Go
108 lines
4.1 KiB
Go
package translation
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"telesrv/internal/domain"
|
|
"telesrv/internal/store/memory"
|
|
)
|
|
|
|
type testLimiter struct{ cost int }
|
|
|
|
func (l *testLimiter) AllowN(_ context.Context, _ string, cost, _ int, _ time.Duration) (bool, int, error) {
|
|
l.cost = cost
|
|
return true, 0, nil
|
|
}
|
|
|
|
type testProvider struct {
|
|
translate func([]domain.TranslationText) ([]domain.TranslationText, error)
|
|
}
|
|
|
|
func (testProvider) Name() string { return "test" }
|
|
func (p testProvider) Translate(_ context.Context, texts []domain.TranslationText, _, _ string) ([]domain.TranslationText, error) {
|
|
return p.translate(texts)
|
|
}
|
|
|
|
type testPrivateMessages struct{ messages []domain.Message }
|
|
|
|
func (s testPrivateMessages) GetMessages(_ context.Context, _ int64, _ []int) (domain.MessageList, error) {
|
|
return domain.MessageList{Messages: append([]domain.Message(nil), s.messages...)}, nil
|
|
}
|
|
|
|
func TestTranslateDirectTextPreservesBatchOrder(t *testing.T) {
|
|
limiter := &testLimiter{}
|
|
svc := NewService(nil, nil, memory.NewDialogStore(), WithRateLimiter(limiter, 60, time.Minute), WithProviders(testProvider{translate: func(in []domain.TranslationText) ([]domain.TranslationText, error) {
|
|
out := make([]domain.TranslationText, len(in))
|
|
for i := range in {
|
|
out[i].Text = "zh:" + in[i].Text
|
|
}
|
|
return out, nil
|
|
}}))
|
|
got, err := svc.Translate(context.Background(), domain.TranslationRequest{
|
|
UserID: 1,
|
|
Texts: []domain.TranslationText{{Text: "one"}, {Text: "two"}},
|
|
ToLang: "zh",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Translate: %v", err)
|
|
}
|
|
if len(got.Texts) != 2 || got.Texts[0].Text != "zh:one" || got.Texts[1].Text != "zh:two" {
|
|
t.Fatalf("Translate result = %#v", got.Texts)
|
|
}
|
|
if limiter.cost != 2 {
|
|
t.Fatalf("rate limit cost = %d, want 2 text items", limiter.cost)
|
|
}
|
|
}
|
|
|
|
func TestTranslateMessageIDsRejectsWrongPeerAndMissingID(t *testing.T) {
|
|
peer := domain.Peer{Type: domain.PeerTypeUser, ID: 2}
|
|
svc := NewService(testPrivateMessages{messages: []domain.Message{
|
|
{ID: 10, Peer: peer, Body: "visible"},
|
|
{ID: 11, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 3}, Body: "wrong peer"},
|
|
}}, nil, memory.NewDialogStore(), WithProviders(testProvider{translate: func(in []domain.TranslationText) ([]domain.TranslationText, error) {
|
|
return in, nil
|
|
}}))
|
|
for _, ids := range [][]int{{10, 11}, {10, 12}} {
|
|
_, err := svc.Translate(context.Background(), domain.TranslationRequest{UserID: 1, Peer: peer, IDs: ids, ToLang: "en"})
|
|
if !errors.Is(err, domain.ErrTranslationMessageInvalid) {
|
|
t.Fatalf("Translate ids %v err = %v, want message invalid", ids, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTranslateRejectsOversizeAndProviderShapeMismatch(t *testing.T) {
|
|
svc := NewService(nil, nil, memory.NewDialogStore(), WithProviders(testProvider{translate: func(in []domain.TranslationText) ([]domain.TranslationText, error) {
|
|
return in[:len(in)-1], nil
|
|
}}))
|
|
texts := make([]domain.TranslationText, domain.MaxTranslationTexts+1)
|
|
for i := range texts {
|
|
texts[i].Text = "x"
|
|
}
|
|
if _, err := svc.Translate(context.Background(), domain.TranslationRequest{UserID: 1, Texts: texts, ToLang: "en"}); !errors.Is(err, domain.ErrTranslationInputTooLong) {
|
|
t.Fatalf("oversize err = %v", err)
|
|
}
|
|
if _, err := svc.Translate(context.Background(), domain.TranslationRequest{UserID: 1, Texts: texts[:2], ToLang: "en"}); !errors.Is(err, domain.ErrTranslationProviderUnavailable) {
|
|
t.Fatalf("shape mismatch err = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestPeerDisabledIsAccountAndPeerScoped(t *testing.T) {
|
|
settings := memory.NewDialogStore()
|
|
svc := NewService(nil, nil, settings)
|
|
peer := domain.Peer{Type: domain.PeerTypeUser, ID: 2}
|
|
if changed, err := svc.SetPeerDisabled(context.Background(), 1, peer, true); err != nil || !changed {
|
|
t.Fatalf("disable = %v/%v", changed, err)
|
|
}
|
|
if disabled, _ := svc.PeerDisabled(context.Background(), 1, peer); !disabled {
|
|
t.Fatal("owner preference not persisted")
|
|
}
|
|
if disabled, _ := svc.PeerDisabled(context.Background(), 2, peer); disabled {
|
|
t.Fatal("preference leaked to another account")
|
|
}
|
|
if changed, err := svc.SetPeerDisabled(context.Background(), 1, peer, false); err != nil || !changed {
|
|
t.Fatalf("enable = %v/%v", changed, err)
|
|
}
|
|
}
|