package localization import ( "context" "errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "tercul/internal/domain" "testing" "gorm.io/gorm" ) // mockTranslationRepository is a local mock for the TranslationRepository interface. type mockTranslationRepository struct { translations []domain.Translation err error } func (m *mockTranslationRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Translation, error) { if m.err != nil { return nil, m.err } var results []domain.Translation for _, t := range m.translations { if t.TranslatableType == "Work" && t.TranslatableID == workID { results = append(results, t) } } return results, nil } func (m *mockTranslationRepository) ListByEntity(ctx context.Context, entityType string, entityID uint) ([]domain.Translation, error) { if m.err != nil { return nil, m.err } var results []domain.Translation for _, t := range m.translations { if t.TranslatableType == entityType && t.TranslatableID == entityID { results = append(results, t) } } return results, nil } // Implement the rest of the TranslationRepository interface with empty methods. func (m *mockTranslationRepository) Create(ctx context.Context, entity *domain.Translation) error { m.translations = append(m.translations, *entity) return nil } func (m *mockTranslationRepository) GetByID(ctx context.Context, id uint) (*domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) Update(ctx context.Context, entity *domain.Translation) error { return nil } func (m *mockTranslationRepository) Delete(ctx context.Context, id uint) error { return nil } func (m *mockTranslationRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Translation], error) { return nil, nil } func (m *mockTranslationRepository) ListAll(ctx context.Context) ([]domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) Count(ctx context.Context) (int64, error) { return 0, nil } func (m *mockTranslationRepository) ListByTranslatorID(ctx context.Context, translatorID uint) ([]domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) ListByStatus(ctx context.Context, status domain.TranslationStatus) ([]domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Translation) error { return nil } func (m *mockTranslationRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Translation) error { return nil } func (m *mockTranslationRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error { return nil } func (m *mockTranslationRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) { return 0, nil } func (m *mockTranslationRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Translation, error) { return nil, nil } func (m *mockTranslationRepository) Exists(ctx context.Context, id uint) (bool, error) { return false, nil } func (m *mockTranslationRepository) BeginTx(ctx context.Context) (*gorm.DB, error) { return nil, nil } func (m *mockTranslationRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error { return nil } type LocalizationServiceSuite struct { suite.Suite repo *mockTranslationRepository service Service } func (s *LocalizationServiceSuite) SetupTest() { s.repo = &mockTranslationRepository{} s.service = NewService(s.repo) } func TestLocalizationServiceSuite(t *testing.T) { suite.Run(t, new(LocalizationServiceSuite)) } func (s *LocalizationServiceSuite) TestGetWorkContent_ZeroWorkID() { content, err := s.service.GetWorkContent(context.Background(), 0, "en") assert.Error(s.T(), err) assert.Equal(s.T(), "invalid work ID", err.Error()) assert.Empty(s.T(), content) } func (s *LocalizationServiceSuite) TestGetWorkContent_NoTranslations() { content, err := s.service.GetWorkContent(context.Background(), 1, "en") assert.NoError(s.T(), err) assert.Empty(s.T(), content) } func (s *LocalizationServiceSuite) TestGetWorkContent_OriginalLanguage() { s.repo.translations = []domain.Translation{ {TranslatableType: "Work", TranslatableID: 1, Language: "es", Content: "Contenido original", IsOriginalLanguage: true}, {TranslatableType: "Work", TranslatableID: 1, Language: "en", Content: "English content", IsOriginalLanguage: false}, } content, err := s.service.GetWorkContent(context.Background(), 1, "fr") assert.NoError(s.T(), err) assert.Equal(s.T(), "Contenido original", content) } func (s *LocalizationServiceSuite) TestGetWorkContent_PreferredLanguage() { s.repo.translations = []domain.Translation{ {TranslatableType: "Work", TranslatableID: 1, Language: "es", Content: "Contenido en español", IsOriginalLanguage: false}, {TranslatableType: "Work", TranslatableID: 1, Language: "en", Content: "English content", IsOriginalLanguage: false}, } content, err := s.service.GetWorkContent(context.Background(), 1, "en") assert.NoError(s.T(), err) assert.Equal(s.T(), "English content", content) } func (s *LocalizationServiceSuite) TestGetWorkContent_Fallback() { s.repo.translations = []domain.Translation{ {TranslatableType: "Work", TranslatableID: 1, Language: "es", Content: "Contenido en español", IsOriginalLanguage: false}, {TranslatableType: "Work", TranslatableID: 1, Language: "fr", Content: "Contenu en français", IsOriginalLanguage: false}, } content, err := s.service.GetWorkContent(context.Background(), 1, "en") assert.NoError(s.T(), err) assert.Equal(s.T(), "Contenido en español", content) } func (s *LocalizationServiceSuite) TestGetWorkContent_RepoError() { s.repo.err = errors.New("database error") content, err := s.service.GetWorkContent(context.Background(), 1, "en") assert.Error(s.T(), err) assert.Equal(s.T(), "database error", err.Error()) assert.Empty(s.T(), content) } func (s *LocalizationServiceSuite) TestGetAuthorBiography_ZeroAuthorID() { content, err := s.service.GetAuthorBiography(context.Background(), 0, "en") assert.Error(s.T(), err) assert.Equal(s.T(), "invalid author ID", err.Error()) assert.Empty(s.T(), content) } func (s *LocalizationServiceSuite) TestGetAuthorBiography_NoTranslations() { content, err := s.service.GetAuthorBiography(context.Background(), 1, "en") assert.NoError(s.T(), err) assert.Empty(s.T(), content) } func (s *LocalizationServiceSuite) TestGetAuthorBiography_OriginalLanguage() { s.repo.translations = []domain.Translation{ {TranslatableType: "Author", TranslatableID: 1, Language: "es", Description: "Biografía original", IsOriginalLanguage: true}, {TranslatableType: "Author", TranslatableID: 1, Language: "en", Description: "English biography", IsOriginalLanguage: false}, } content, err := s.service.GetAuthorBiography(context.Background(), 1, "fr") assert.NoError(s.T(), err) assert.Equal(s.T(), "Biografía original", content) } func (s *LocalizationServiceSuite) TestGetAuthorBiography_PreferredLanguage() { s.repo.translations = []domain.Translation{ {TranslatableType: "Author", TranslatableID: 1, Language: "es", Description: "Biografía en español", IsOriginalLanguage: false}, {TranslatableType: "Author", TranslatableID: 1, Language: "en", Description: "English biography", IsOriginalLanguage: false}, } content, err := s.service.GetAuthorBiography(context.Background(), 1, "en") assert.NoError(s.T(), err) assert.Equal(s.T(), "English biography", content) } func (s *LocalizationServiceSuite) TestGetAuthorBiography_Fallback() { s.repo.translations = []domain.Translation{ {TranslatableType: "Author", TranslatableID: 1, Language: "es", Description: "Biografía en español", IsOriginalLanguage: false}, {TranslatableType: "Author", TranslatableID: 1, Language: "fr", Description: "Biographie en français", IsOriginalLanguage: false}, } content, err := s.service.GetAuthorBiography(context.Background(), 1, "en") assert.NoError(s.T(), err) assert.Equal(s.T(), "Biografía en español", content) } func (s *LocalizationServiceSuite) TestGetAuthorBiography_NoDescription() { s.repo.translations = []domain.Translation{ {TranslatableType: "Author", TranslatableID: 1, Language: "es", Content: "Contenido sin descripción", IsOriginalLanguage: false}, } content, err := s.service.GetAuthorBiography(context.Background(), 1, "en") assert.NoError(s.T(), err) assert.Empty(s.T(), content) } func (s *LocalizationServiceSuite) TestGetAuthorBiography_RepoError() { s.repo.err = errors.New("database error") content, err := s.service.GetAuthorBiography(context.Background(), 1, "en") assert.Error(s.T(), err) assert.Equal(s.T(), "database error", err.Error()) assert.Empty(s.T(), content) }