package sql_test import ( "context" "tercul/internal/data/sql" "tercul/internal/domain" "tercul/internal/platform/config" "tercul/internal/testutil" "testing" "github.com/stretchr/testify/suite" ) type BookRepositoryTestSuite struct { testutil.IntegrationTestSuite BookRepo domain.BookRepository } func (s *BookRepositoryTestSuite) SetupSuite() { s.IntegrationTestSuite.SetupSuite(testutil.DefaultTestConfig()) cfg, err := config.LoadConfig() s.Require().NoError(err) s.BookRepo = sql.NewBookRepository(s.DB, cfg) } func (s *BookRepositoryTestSuite) SetupTest() { s.IntegrationTestSuite.SetupTest() s.DB.Exec("DELETE FROM books") s.DB.Exec("DELETE FROM authors") s.DB.Exec("DELETE FROM publishers") s.DB.Exec("DELETE FROM book_authors") s.DB.Exec("DELETE FROM book_works") s.DB.Exec("DELETE FROM works") } func (s *BookRepositoryTestSuite) createBook(title, isbn string) *domain.Book { book := &domain.Book{ Title: title, ISBN: isbn, TranslatableModel: domain.TranslatableModel{ Language: "en", }, } err := s.BookRepo.Create(context.Background(), book) s.Require().NoError(err) return book } func (s *BookRepositoryTestSuite) createAuthor(name string) *domain.Author { author := &domain.Author{Name: name} err := s.DB.Create(author).Error s.Require().NoError(err) return author } func (s *BookRepositoryTestSuite) createPublisher(name string) *domain.Publisher { publisher := &domain.Publisher{Name: name} err := s.DB.Create(publisher).Error s.Require().NoError(err) return publisher } func (s *BookRepositoryTestSuite) TestFindByISBN() { s.Run("should return a book by ISBN", func() { // Arrange s.createBook("Test Book", "1234567890") // Act foundBook, err := s.BookRepo.FindByISBN(context.Background(), "1234567890") // Assert s.Require().NoError(err) s.Require().NotNil(foundBook) s.Equal("Test Book", foundBook.Title) }) s.Run("should return error if ISBN not found", func() { // Arrange s.createBook("Another Book", "1111111111") // Act _, err := s.BookRepo.FindByISBN(context.Background(), "9999999999") // Assert s.Require().Error(err) }) } func TestBookRepository(t *testing.T) { suite.Run(t, new(BookRepositoryTestSuite)) } func (s *BookRepositoryTestSuite) TestListByAuthorID() { s.Run("should return all books for a given author", func() { // Arrange author1 := s.createAuthor("Test Author 1") author2 := s.createAuthor("Test Author 2") book1 := s.createBook("Book 1 by Author 1", "111") book2 := s.createBook("Book 2 by Author 1", "222") book3 := s.createBook("Book 3 by Author 2", "333") s.Require().NoError(s.DB.Model(&author1).Association("Books").Append([]*domain.Book{book1, book2})) s.Require().NoError(s.DB.Model(&author2).Association("Books").Append(book3)) // Act books, err := s.BookRepo.ListByAuthorID(context.Background(), author1.ID) // Assert s.Require().NoError(err) s.Len(books, 2) s.ElementsMatch([]string{"Book 1 by Author 1", "Book 2 by Author 1"}, []string{books[0].Title, books[1].Title}) }) } func (s *BookRepositoryTestSuite) TestListByPublisherID() { s.Run("should return all books for a given publisher", func() { // Arrange publisher1 := s.createPublisher("Publisher 1") publisher2 := s.createPublisher("Publisher 2") book1 := s.createBook("Book 1 from Publisher 1", "111") book2 := s.createBook("Book 2 from Publisher 1", "222") book3 := s.createBook("Book 3 from Publisher 2", "333") book1.PublisherID = &publisher1.ID book2.PublisherID = &publisher1.ID book3.PublisherID = &publisher2.ID s.Require().NoError(s.DB.Save(book1).Error) s.Require().NoError(s.DB.Save(book2).Error) s.Require().NoError(s.DB.Save(book3).Error) // Act books, err := s.BookRepo.ListByPublisherID(context.Background(), publisher1.ID) // Assert s.Require().NoError(err) s.Len(books, 2) s.ElementsMatch([]string{"Book 1 from Publisher 1", "Book 2 from Publisher 1"}, []string{books[0].Title, books[1].Title}) }) } func (s *BookRepositoryTestSuite) TestListByWorkID() { s.Run("should return all books associated with a given work", func() { // Arrange work1 := s.CreateTestWork(s.AdminCtx, "Work 1", "en", "content 1") work2 := s.CreateTestWork(s.AdminCtx, "Work 2", "en", "content 2") book1 := s.createBook("Book 1 for Work 1", "111") book2 := s.createBook("Book 2 for Work 1", "222") book3 := s.createBook("Book 3 for Work 2", "333") // Manually create the association in the join table s.Require().NoError(s.DB.Exec("INSERT INTO book_works (book_id, work_id) VALUES (?, ?)", book1.ID, work1.ID).Error) s.Require().NoError(s.DB.Exec("INSERT INTO book_works (book_id, work_id) VALUES (?, ?)", book2.ID, work1.ID).Error) s.Require().NoError(s.DB.Exec("INSERT INTO book_works (book_id, work_id) VALUES (?, ?)", book3.ID, work2.ID).Error) // Act books, err := s.BookRepo.ListByWorkID(context.Background(), work1.ID) // Assert s.Require().NoError(err) s.Len(books, 2) s.ElementsMatch([]string{"Book 1 for Work 1", "Book 2 for Work 1"}, []string{books[0].Title, books[1].Title}) }) }