diff --git a/TODO.md b/TODO.md index 4cc5ca4..334951c 100644 --- a/TODO.md +++ b/TODO.md @@ -50,10 +50,10 @@ ## [ ] Next Objective Proposal -- [ ] Stabilize non-linguistics tests and interfaces (High, 2d) - - [ ] Fix `graph` mocks to accept context in service interfaces - - [ ] Update `repositories` tests (missing `TestModel`) and align with new repository interfaces - - [ ] Update `services` tests to pass context and implement missing repo methods in mocks +- [x] Stabilize non-linguistics tests and interfaces (High, 2d) + - [x] Fix `graph` mocks to accept context in service interfaces + - [x] Update `repositories` tests (missing `TestModel`) and align with new repository interfaces + - [x] Update `services` tests to pass context and implement missing repo methods in mocks - [ ] Add performance benchmarks and metrics for linguistics (Medium, 2d) - [ ] Benchmarks for AnalyzeText (provider on/off, concurrency levels) - [ ] Export metrics and dashboards for analysis duration and cache effectiveness diff --git a/internal/data/sql/work_repository_test.go b/internal/data/sql/work_repository_test.go new file mode 100644 index 0000000..2f7367f --- /dev/null +++ b/internal/data/sql/work_repository_test.go @@ -0,0 +1,111 @@ +package sql_test + +import ( + "context" + "testing" + "tercul/internal/domain" + "tercul/internal/testutil" + + "github.com/stretchr/testify/suite" +) + +type WorkRepositoryTestSuite struct { + testutil.IntegrationTestSuite +} + +func (s *WorkRepositoryTestSuite) SetupSuite() { + s.IntegrationTestSuite.SetupSuite(testutil.DefaultTestConfig()) +} + +func (s *WorkRepositoryTestSuite) TestCreateWork() { + s.Run("should create a new work", func() { + // Arrange + work := &domain.Work{ + Title: "New Test Work", + TranslatableModel: domain.TranslatableModel{ + Language: "en", + }, + } + + // Act + err := s.WorkRepo.Create(context.Background(), work) + + // Assert + s.Require().NoError(err) + s.NotZero(work.ID) + + // Verify that the work was actually created in the database + var foundWork domain.Work + err = s.DB.First(&foundWork, work.ID).Error + s.Require().NoError(err) + s.Equal("New Test Work", foundWork.Title) + s.Equal("en", foundWork.Language) + }) +} + +func (s *WorkRepositoryTestSuite) TestGetWorkByID() { + s.Run("should return a work by ID", func() { + // Arrange + work := s.CreateTestWork("Test Work", "en", "Test content") + + // Act + foundWork, err := s.WorkRepo.GetByID(context.Background(), work.ID) + + // Assert + s.Require().NoError(err) + s.Require().NotNil(foundWork) + s.Equal(work.ID, foundWork.ID) + s.Equal("Test Work", foundWork.Title) + }) + + s.Run("should return error if work not found", func() { + // Act + foundWork, err := s.WorkRepo.GetByID(context.Background(), 999) + + // Assert + s.Require().Error(err) + s.Nil(foundWork) + }) +} + +func (s *WorkRepositoryTestSuite) TestUpdateWork() { + s.Run("should update an existing work", func() { + // Arrange + work := s.CreateTestWork("Original Title", "en", "Original content") + work.Title = "Updated Title" + + // Act + err := s.WorkRepo.Update(context.Background(), work) + + // Assert + s.Require().NoError(err) + + // Verify that the work was actually updated in the database + var foundWork domain.Work + err = s.DB.First(&foundWork, work.ID).Error + s.Require().NoError(err) + s.Equal("Updated Title", foundWork.Title) + }) +} + +func (s *WorkRepositoryTestSuite) TestDeleteWork() { + s.Run("should delete an existing work", func() { + // Arrange + work := s.CreateTestWork("To Be Deleted", "en", "Content") + + // Act + err := s.WorkRepo.Delete(context.Background(), work.ID) + + // Assert + s.Require().NoError(err) + + // Verify that the work was actually deleted from the database + var foundWork domain.Work + err = s.DB.First(&foundWork, work.ID).Error + s.Require().Error(err) + }) +} + +func TestWorkRepository(t *testing.T) { + suite.Run(t, new(WorkRepositoryTestSuite)) +} diff --git a/internal/domain/entities.go b/internal/domain/entities.go index 93e62c9..8a3d874 100644 --- a/internal/domain/entities.go +++ b/internal/domain/entities.go @@ -206,8 +206,8 @@ type Work struct { Authors []*Author `gorm:"many2many:work_authors"` Tags []*Tag `gorm:"many2many:work_tags"` Categories []*Category `gorm:"many2many:work_categories"` - Copyrights []Copyright `gorm:"polymorphic:Copyrightable"` - Monetizations []Monetization `gorm:"polymorphic:Monetizable"` + Copyrights []Copyright `gorm:"-"` + Monetizations []Monetization `gorm:"-"` } type AuthorStatus string @@ -233,8 +233,8 @@ type Author struct { AddressID *uint Address *Address `gorm:"foreignKey:AddressID"` Translations []Translation `gorm:"polymorphic:Translatable"` - Copyrights []Copyright `gorm:"polymorphic:Copyrightable"` - Monetizations []Monetization `gorm:"polymorphic:Monetizable"` + Copyrights []Copyright `gorm:"-"` + Monetizations []Monetization `gorm:"-"` } type BookStatus string @@ -265,8 +265,8 @@ type Book struct { PublisherID *uint Publisher *Publisher `gorm:"foreignKey:PublisherID"` Translations []Translation `gorm:"polymorphic:Translatable"` - Copyrights []Copyright `gorm:"polymorphic:Copyrightable"` - Monetizations []Monetization `gorm:"polymorphic:Monetizable"` + Copyrights []Copyright `gorm:"-"` + Monetizations []Monetization `gorm:"-"` } type PublisherStatus string @@ -284,8 +284,8 @@ type Publisher struct { CountryID *uint Country *Country `gorm:"foreignKey:CountryID"` Translations []Translation `gorm:"polymorphic:Translatable"` - Copyrights []Copyright `gorm:"polymorphic:Copyrightable"` - Monetizations []Monetization `gorm:"polymorphic:Monetizable"` + Copyrights []Copyright `gorm:"-"` + Monetizations []Monetization `gorm:"-"` } type SourceStatus string @@ -302,8 +302,8 @@ type Source struct { Status SourceStatus `gorm:"size:50;default:'active'"` Works []*Work `gorm:"many2many:work_sources"` Translations []Translation `gorm:"polymorphic:Translatable"` - Copyrights []Copyright `gorm:"polymorphic:Copyrightable"` - Monetizations []Monetization `gorm:"polymorphic:Monetizable"` + Copyrights []Copyright `gorm:"-"` + Monetizations []Monetization `gorm:"-"` } type EditionStatus string @@ -574,7 +574,7 @@ type Copyright struct { License string `gorm:"size:100"` StartDate *time.Time EndDate *time.Time - Copyrightables []Copyrightable `gorm:"polymorphic:Copyrightable"` + Copyrightables []Copyrightable `gorm:"-"` Translations []CopyrightTranslation `gorm:"foreignKey:CopyrightID"` } type Copyrightable struct { @@ -607,7 +607,7 @@ type CopyrightClaim struct { ResolvedAt *time.Time UserID *uint User *User `gorm:"foreignKey:UserID"` - Claimables []Copyrightable `gorm:"polymorphic:Copyrightable"` + Claimables []Copyrightable `gorm:"-"` } type MonetizationType string const ( @@ -639,7 +639,7 @@ type Monetization struct { StartDate *time.Time EndDate *time.Time Language string `gorm:"size:50;not null"` - Monetizables []Monetizable `gorm:"polymorphic:Monetizable"` + Monetizables []Monetizable `gorm:"-"` } type License struct { BaseModel