package translation_test import ( "context" "testing" "tercul/internal/app/authz" "tercul/internal/app/translation" "tercul/internal/domain" "tercul/internal/domain/work" platform_auth "tercul/internal/platform/auth" "tercul/internal/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" ) type TranslationCommandsTestSuite struct { suite.Suite mockWorkRepo *testutil.MockWorkRepository mockTranslationRepo *testutil.MockTranslationRepository authzSvc *authz.Service cmd *translation.TranslationCommands adminCtx context.Context userCtx context.Context adminUser *domain.User regularUser *domain.User } func (s *TranslationCommandsTestSuite) SetupTest() { s.mockWorkRepo = new(testutil.MockWorkRepository) s.mockTranslationRepo = new(testutil.MockTranslationRepository) s.authzSvc = authz.NewService(s.mockWorkRepo, s.mockTranslationRepo) s.cmd = translation.NewTranslationCommands(s.mockTranslationRepo, s.authzSvc) s.adminUser = &domain.User{BaseModel: domain.BaseModel{ID: 1}, Role: domain.UserRoleAdmin} s.regularUser = &domain.User{BaseModel: domain.BaseModel{ID: 2}, Role: domain.UserRoleContributor} s.adminCtx = context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{ UserID: s.adminUser.ID, Role: string(s.adminUser.Role), }) s.userCtx = context.WithValue(context.Background(), platform_auth.ClaimsContextKey, &platform_auth.Claims{ UserID: s.regularUser.ID, Role: string(s.regularUser.Role), }) } func (s *TranslationCommandsTestSuite) TestCreateOrUpdateTranslation() { testWork := &work.Work{ TranslatableModel: domain.TranslatableModel{BaseModel: domain.BaseModel{ID: 1}}, } input := translation.CreateOrUpdateTranslationInput{ Title: "Test Title", Content: "Test content", Language: "es", TranslatableID: testWork.ID, TranslatableType: "works", } s.Run("should create translation for admin", func() { // Arrange s.mockWorkRepo.On("GetByID", mock.Anything, testWork.ID).Return(testWork, nil).Once() s.mockTranslationRepo.On("Upsert", mock.Anything, mock.AnythingOfType("*domain.Translation")).Return(nil).Once() // Act result, err := s.cmd.CreateOrUpdateTranslation(s.adminCtx, input) // Assert s.NoError(err) s.NotNil(result) s.Equal(input.Title, result.Title) s.Equal(s.adminUser.ID, *result.TranslatorID) s.mockWorkRepo.AssertExpectations(s.T()) s.mockTranslationRepo.AssertExpectations(s.T()) }) s.Run("should create translation for author", func() { // Arrange s.mockWorkRepo.On("GetByID", mock.Anything, testWork.ID).Return(testWork, nil).Once() s.mockWorkRepo.On("IsAuthor", mock.Anything, testWork.ID, s.regularUser.ID).Return(true, nil).Once() s.mockTranslationRepo.On("Upsert", mock.Anything, mock.AnythingOfType("*domain.Translation")).Return(nil).Once() // Act result, err := s.cmd.CreateOrUpdateTranslation(s.userCtx, input) // Assert s.NoError(err) s.NotNil(result) s.Equal(input.Title, result.Title) s.Equal(s.regularUser.ID, *result.TranslatorID) s.mockWorkRepo.AssertExpectations(s.T()) s.mockTranslationRepo.AssertExpectations(s.T()) }) s.Run("should fail if user is not authorized", func() { // Arrange s.mockWorkRepo.On("GetByID", mock.Anything, testWork.ID).Return(testWork, nil).Once() s.mockWorkRepo.On("IsAuthor", mock.Anything, testWork.ID, s.regularUser.ID).Return(false, nil).Once() // Act _, err := s.cmd.CreateOrUpdateTranslation(s.userCtx, input) // Assert s.Error(err) s.ErrorIs(err, domain.ErrForbidden) s.mockWorkRepo.AssertExpectations(s.T()) }) s.Run("should fail on validation error for empty language", func() { // Arrange invalidInput := input invalidInput.Language = "" // Act _, err := s.cmd.CreateOrUpdateTranslation(s.userCtx, invalidInput) // Assert s.Error(err) assert.ErrorContains(s.T(), err, "language cannot be empty") }) } func TestTranslationCommands(t *testing.T) { suite.Run(t, new(TranslationCommandsTestSuite)) }