mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
147 lines
5.4 KiB
Go
147 lines
5.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
)
|
|
|
|
// minimal mocks
|
|
type mockLocRepo struct {
|
|
fieldValues map[string]string // key: entityID|field -> value
|
|
idsByField map[string][]string
|
|
}
|
|
|
|
func (m *mockLocRepo) GetEntitiesNeedingTranslation(ctx context.Context, entityType, field, targetLocale string, limit int) ([]string, error) {
|
|
return m.idsByField[field], nil
|
|
}
|
|
|
|
func (m *mockLocRepo) GetEntityFieldValue(ctx context.Context, entityType, entityID, field string) (string, error) {
|
|
k := entityID + "|" + field
|
|
return m.fieldValues[k], nil
|
|
}
|
|
|
|
func (m *mockLocRepo) FindExistingTranslationByRussianText(ctx context.Context, entityType, field, targetLocale, russianText string) (string, error) {
|
|
return "", nil
|
|
}
|
|
|
|
// Unused methods to satisfy interface - implement as noops
|
|
func (m *mockLocRepo) Create(ctx context.Context, loc *domain.Localization) error { return nil }
|
|
func (m *mockLocRepo) GetByEntityAndField(ctx context.Context, entityType, entityID, field, locale string) (*domain.Localization, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocRepo) GetAllByEntity(ctx context.Context, entityType, entityID string) ([]*domain.Localization, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocRepo) Update(ctx context.Context, loc *domain.Localization) error { return nil }
|
|
func (m *mockLocRepo) Delete(ctx context.Context, id string) error { return nil }
|
|
func (m *mockLocRepo) GetByEntityTypeAndLocale(ctx context.Context, entityType, locale string) ([]*domain.Localization, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocRepo) GetAllLocales(ctx context.Context) ([]string, error) { return nil, nil }
|
|
func (m *mockLocRepo) GetSupportedLocalesForEntity(ctx context.Context, entityType, entityID string) ([]string, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocRepo) BulkCreate(ctx context.Context, localizations []*domain.Localization) error {
|
|
return nil
|
|
}
|
|
func (m *mockLocRepo) BulkDelete(ctx context.Context, ids []string) error { return nil }
|
|
func (m *mockLocRepo) SearchLocalizations(ctx context.Context, query string, locale string, limit int) ([]*domain.Localization, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocRepo) GetTranslationReuseCandidates(ctx context.Context, entityType, field, locale string) ([]domain.ReuseCandidate, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocRepo) GetTranslationCountsByEntity(ctx context.Context) (map[string]map[string]int, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
// fake roundtripper to mock HTTP responses from the translation service
|
|
type fakeRoundTripper struct {
|
|
responseBody string
|
|
}
|
|
|
|
func (f *fakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
body := io.NopCloser(strings.NewReader(f.responseBody))
|
|
return &http.Response{StatusCode: 200, Body: body, Header: http.Header{"Content-Type": {"application/json"}}}, nil
|
|
}
|
|
|
|
type mockLocService struct {
|
|
saved map[string]string // key: entityID|field|locale -> value
|
|
}
|
|
|
|
func (m *mockLocService) GetLocalizedValue(entityType, entityID, field, locale string) (string, error) {
|
|
return "", nil
|
|
}
|
|
func (m *mockLocService) SetLocalizedValue(entityType, entityID, field, locale, value string) error {
|
|
k := entityID + "|" + field + "|" + locale
|
|
m.saved[k] = value
|
|
return nil
|
|
}
|
|
func (m *mockLocService) GetAllLocalizedValues(entityType, entityID string) (map[string]map[string]string, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocService) GetLocalizedEntity(entityType, entityID, locale string) (map[string]string, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocService) GetSupportedLocalesForEntity(entityType, entityID string) ([]string, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocService) DeleteLocalizedValue(entityType, entityID, field, locale string) error {
|
|
return nil
|
|
}
|
|
func (m *mockLocService) BulkSetLocalizedValues(entityType, entityID string, values map[string]map[string]string) error {
|
|
return nil
|
|
}
|
|
func (m *mockLocService) GetAllLocales() ([]string, error) { return nil, nil }
|
|
func (m *mockLocService) SearchLocalizations(query, locale string, limit int) ([]*domain.Localization, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockLocService) ApplyLocalizationToEntity(entity domain.Localizable, locale string) error {
|
|
return nil
|
|
}
|
|
|
|
func TestBulkTranslateData_Simple(t *testing.T) {
|
|
locRepo := &mockLocRepo{
|
|
fieldValues: map[string]string{"org-1|name": "Пример"},
|
|
idsByField: map[string][]string{"name": {"org-1"}},
|
|
}
|
|
|
|
locSvc := &mockLocService{saved: make(map[string]string)}
|
|
// create a TranslationService with a fake client that returns canned response
|
|
ts := NewTranslationService("http://fake-ollama", "test-model")
|
|
ts.client = &http.Client{Transport: &fakeRoundTripper{responseBody: `{"model":"test","response":"translated:Пример:en","done":true}`}}
|
|
|
|
cache := NewTranslationCacheService(locRepo, locSvc)
|
|
|
|
svc := &I18nService{
|
|
locService: locSvc,
|
|
locRepo: locRepo,
|
|
translationSvc: ts,
|
|
cacheService: cache,
|
|
}
|
|
|
|
results, err := svc.BulkTranslateData(context.Background(), "organization", nil, "en", []string{"name"})
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got %v", err)
|
|
}
|
|
|
|
if len(results) != 1 {
|
|
t.Fatalf("expected results for 1 entity, got %d", len(results))
|
|
}
|
|
|
|
if results["org-1"]["name"] != "translated:Пример:en" {
|
|
t.Fatalf("unexpected translation: %v", results["org-1"]["name"])
|
|
}
|
|
|
|
// Check that translation was saved via locService
|
|
saved := locSvc.saved["org-1|name|en"]
|
|
if saved != "translated:Пример:en" {
|
|
t.Fatalf("expected saved translation, got %v", saved)
|
|
}
|
|
}
|