diff --git a/module/feature/review/mocks/HandlerReviewInterface.go b/module/feature/review/mocks/HandlerReviewInterface.go new file mode 100644 index 0000000..ec1dab6 --- /dev/null +++ b/module/feature/review/mocks/HandlerReviewInterface.go @@ -0,0 +1,91 @@ +// Code generated by mockery v2.36.1. DO NOT EDIT. + +package mocks + +import ( + echo "github.com/labstack/echo/v4" + mock "github.com/stretchr/testify/mock" +) + +// HandlerReviewInterface is an autogenerated mock type for the HandlerReviewInterface type +type HandlerReviewInterface struct { + mock.Mock +} + +// CreateReview provides a mock function with given fields: +func (_m *HandlerReviewInterface) CreateReview() echo.HandlerFunc { + ret := _m.Called() + + var r0 echo.HandlerFunc + if rf, ok := ret.Get(0).(func() echo.HandlerFunc); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(echo.HandlerFunc) + } + } + + return r0 +} + +// CreateReviewImages provides a mock function with given fields: +func (_m *HandlerReviewInterface) CreateReviewImages() echo.HandlerFunc { + ret := _m.Called() + + var r0 echo.HandlerFunc + if rf, ok := ret.Get(0).(func() echo.HandlerFunc); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(echo.HandlerFunc) + } + } + + return r0 +} + +// GetDetailReviewProduct provides a mock function with given fields: +func (_m *HandlerReviewInterface) GetDetailReviewProduct() echo.HandlerFunc { + ret := _m.Called() + + var r0 echo.HandlerFunc + if rf, ok := ret.Get(0).(func() echo.HandlerFunc); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(echo.HandlerFunc) + } + } + + return r0 +} + +// GetReviewById provides a mock function with given fields: +func (_m *HandlerReviewInterface) GetReviewById() echo.HandlerFunc { + ret := _m.Called() + + var r0 echo.HandlerFunc + if rf, ok := ret.Get(0).(func() echo.HandlerFunc); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(echo.HandlerFunc) + } + } + + return r0 +} + +// NewHandlerReviewInterface creates a new instance of HandlerReviewInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewHandlerReviewInterface(t interface { + mock.TestingT + Cleanup(func()) +}) *HandlerReviewInterface { + mock := &HandlerReviewInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/module/feature/review/mocks/RepositoryReviewInterface.go b/module/feature/review/mocks/RepositoryReviewInterface.go new file mode 100644 index 0000000..771298c --- /dev/null +++ b/module/feature/review/mocks/RepositoryReviewInterface.go @@ -0,0 +1,155 @@ +// Code generated by mockery v2.36.1. DO NOT EDIT. + +package mocks + +import ( + entities "github.com/capstone-kelompok-7/backend-disappear/module/entities" + mock "github.com/stretchr/testify/mock" +) + +// RepositoryReviewInterface is an autogenerated mock type for the RepositoryReviewInterface type +type RepositoryReviewInterface struct { + mock.Mock +} + +// CountAverageRating provides a mock function with given fields: productID +func (_m *RepositoryReviewInterface) CountAverageRating(productID uint64) (float64, error) { + ret := _m.Called(productID) + + var r0 float64 + var r1 error + if rf, ok := ret.Get(0).(func(uint64) (float64, error)); ok { + return rf(productID) + } + if rf, ok := ret.Get(0).(func(uint64) float64); ok { + r0 = rf(productID) + } else { + r0 = ret.Get(0).(float64) + } + + if rf, ok := ret.Get(1).(func(uint64) error); ok { + r1 = rf(productID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateReview provides a mock function with given fields: newData +func (_m *RepositoryReviewInterface) CreateReview(newData *entities.ReviewModels) (*entities.ReviewModels, error) { + ret := _m.Called(newData) + + var r0 *entities.ReviewModels + var r1 error + if rf, ok := ret.Get(0).(func(*entities.ReviewModels) (*entities.ReviewModels, error)); ok { + return rf(newData) + } + if rf, ok := ret.Get(0).(func(*entities.ReviewModels) *entities.ReviewModels); ok { + r0 = rf(newData) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ReviewModels) + } + } + + if rf, ok := ret.Get(1).(func(*entities.ReviewModels) error); ok { + r1 = rf(newData) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateReviewImages provides a mock function with given fields: newData +func (_m *RepositoryReviewInterface) CreateReviewImages(newData *entities.ReviewPhotoModels) (*entities.ReviewPhotoModels, error) { + ret := _m.Called(newData) + + var r0 *entities.ReviewPhotoModels + var r1 error + if rf, ok := ret.Get(0).(func(*entities.ReviewPhotoModels) (*entities.ReviewPhotoModels, error)); ok { + return rf(newData) + } + if rf, ok := ret.Get(0).(func(*entities.ReviewPhotoModels) *entities.ReviewPhotoModels); ok { + r0 = rf(newData) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ReviewPhotoModels) + } + } + + if rf, ok := ret.Get(1).(func(*entities.ReviewPhotoModels) error); ok { + r1 = rf(newData) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetReviewsById provides a mock function with given fields: reviewID +func (_m *RepositoryReviewInterface) GetReviewsById(reviewID uint64) (*entities.ReviewModels, error) { + ret := _m.Called(reviewID) + + var r0 *entities.ReviewModels + var r1 error + if rf, ok := ret.Get(0).(func(uint64) (*entities.ReviewModels, error)); ok { + return rf(reviewID) + } + if rf, ok := ret.Get(0).(func(uint64) *entities.ReviewModels); ok { + r0 = rf(reviewID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ReviewModels) + } + } + + if rf, ok := ret.Get(1).(func(uint64) error); ok { + r1 = rf(reviewID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetReviewsProductByID provides a mock function with given fields: productID +func (_m *RepositoryReviewInterface) GetReviewsProductByID(productID uint64) (*entities.ProductModels, error) { + ret := _m.Called(productID) + + var r0 *entities.ProductModels + var r1 error + if rf, ok := ret.Get(0).(func(uint64) (*entities.ProductModels, error)); ok { + return rf(productID) + } + if rf, ok := ret.Get(0).(func(uint64) *entities.ProductModels); ok { + r0 = rf(productID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ProductModels) + } + } + + if rf, ok := ret.Get(1).(func(uint64) error); ok { + r1 = rf(productID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewRepositoryReviewInterface creates a new instance of RepositoryReviewInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewRepositoryReviewInterface(t interface { + mock.TestingT + Cleanup(func()) +}) *RepositoryReviewInterface { + mock := &RepositoryReviewInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/module/feature/review/mocks/ServiceReviewInterface.go b/module/feature/review/mocks/ServiceReviewInterface.go new file mode 100644 index 0000000..1bae3da --- /dev/null +++ b/module/feature/review/mocks/ServiceReviewInterface.go @@ -0,0 +1,155 @@ +// Code generated by mockery v2.36.1. DO NOT EDIT. + +package mocks + +import ( + entities "github.com/capstone-kelompok-7/backend-disappear/module/entities" + mock "github.com/stretchr/testify/mock" +) + +// ServiceReviewInterface is an autogenerated mock type for the ServiceReviewInterface type +type ServiceReviewInterface struct { + mock.Mock +} + +// CountAverageRating provides a mock function with given fields: productID +func (_m *ServiceReviewInterface) CountAverageRating(productID uint64) (float64, error) { + ret := _m.Called(productID) + + var r0 float64 + var r1 error + if rf, ok := ret.Get(0).(func(uint64) (float64, error)); ok { + return rf(productID) + } + if rf, ok := ret.Get(0).(func(uint64) float64); ok { + r0 = rf(productID) + } else { + r0 = ret.Get(0).(float64) + } + + if rf, ok := ret.Get(1).(func(uint64) error); ok { + r1 = rf(productID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateReview provides a mock function with given fields: newData +func (_m *ServiceReviewInterface) CreateReview(newData *entities.ReviewModels) (*entities.ReviewModels, error) { + ret := _m.Called(newData) + + var r0 *entities.ReviewModels + var r1 error + if rf, ok := ret.Get(0).(func(*entities.ReviewModels) (*entities.ReviewModels, error)); ok { + return rf(newData) + } + if rf, ok := ret.Get(0).(func(*entities.ReviewModels) *entities.ReviewModels); ok { + r0 = rf(newData) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ReviewModels) + } + } + + if rf, ok := ret.Get(1).(func(*entities.ReviewModels) error); ok { + r1 = rf(newData) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateReviewImages provides a mock function with given fields: reviewData +func (_m *ServiceReviewInterface) CreateReviewImages(reviewData *entities.ReviewPhotoModels) (*entities.ReviewPhotoModels, error) { + ret := _m.Called(reviewData) + + var r0 *entities.ReviewPhotoModels + var r1 error + if rf, ok := ret.Get(0).(func(*entities.ReviewPhotoModels) (*entities.ReviewPhotoModels, error)); ok { + return rf(reviewData) + } + if rf, ok := ret.Get(0).(func(*entities.ReviewPhotoModels) *entities.ReviewPhotoModels); ok { + r0 = rf(reviewData) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ReviewPhotoModels) + } + } + + if rf, ok := ret.Get(1).(func(*entities.ReviewPhotoModels) error); ok { + r1 = rf(reviewData) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetReviewById provides a mock function with given fields: reviewID +func (_m *ServiceReviewInterface) GetReviewById(reviewID uint64) (*entities.ReviewModels, error) { + ret := _m.Called(reviewID) + + var r0 *entities.ReviewModels + var r1 error + if rf, ok := ret.Get(0).(func(uint64) (*entities.ReviewModels, error)); ok { + return rf(reviewID) + } + if rf, ok := ret.Get(0).(func(uint64) *entities.ReviewModels); ok { + r0 = rf(reviewID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ReviewModels) + } + } + + if rf, ok := ret.Get(1).(func(uint64) error); ok { + r1 = rf(reviewID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetReviewsProductByID provides a mock function with given fields: productID +func (_m *ServiceReviewInterface) GetReviewsProductByID(productID uint64) (*entities.ProductModels, error) { + ret := _m.Called(productID) + + var r0 *entities.ProductModels + var r1 error + if rf, ok := ret.Get(0).(func(uint64) (*entities.ProductModels, error)); ok { + return rf(productID) + } + if rf, ok := ret.Get(0).(func(uint64) *entities.ProductModels); ok { + r0 = rf(productID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entities.ProductModels) + } + } + + if rf, ok := ret.Get(1).(func(uint64) error); ok { + r1 = rf(productID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewServiceReviewInterface creates a new instance of ServiceReviewInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewServiceReviewInterface(t interface { + mock.TestingT + Cleanup(func()) +}) *ServiceReviewInterface { + mock := &ServiceReviewInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/module/feature/review/service/service_test.go b/module/feature/review/service/service_test.go new file mode 100644 index 0000000..8553b6a --- /dev/null +++ b/module/feature/review/service/service_test.go @@ -0,0 +1,379 @@ +package service + +import ( + "errors" + "testing" + "time" + + "github.com/capstone-kelompok-7/backend-disappear/config" + "github.com/capstone-kelompok-7/backend-disappear/module/entities" + "github.com/capstone-kelompok-7/backend-disappear/module/feature/assistant" + assistantMocks "github.com/capstone-kelompok-7/backend-disappear/module/feature/assistant/mocks" + assistants "github.com/capstone-kelompok-7/backend-disappear/module/feature/assistant/service" + "github.com/capstone-kelompok-7/backend-disappear/module/feature/product" + productsMocks "github.com/capstone-kelompok-7/backend-disappear/module/feature/product/mocks" + products "github.com/capstone-kelompok-7/backend-disappear/module/feature/product/service" + "github.com/capstone-kelompok-7/backend-disappear/module/feature/review" + "github.com/capstone-kelompok-7/backend-disappear/module/feature/review/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func setupTestService(t *testing.T) (*mocks.RepositoryReviewInterface, review.ServiceReviewInterface, product.ServiceProductInterface, assistant.ServiceAssistantInterface) { + repo := mocks.NewRepositoryReviewInterface(t) + repoProduct := productsMocks.NewRepositoryProductInterface(t) + repoAssistant := assistantMocks.NewRepositoryAssistantInterface(t) + + assistantService := assistants.NewAssistantService(repoAssistant, nil, config.Config{}) + productService := products.NewProductService(repoProduct, assistantService) + reviewService := NewReviewService(repo, productService) + + return repo, reviewService, productService, assistantService +} + +func TestCreateReview(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + + reviewData := &entities.ReviewModels{ + UserID: 2, + ProductID: 2, + Rating: 4, + Description: "Great product!", + Date: time.Now(), + CreatedAt: time.Now(), + } + + productServiceMock := productsMocks.NewServiceProductInterface(t) + product := &entities.ProductModels{ + ID: 2, + Name: "Product ABC", + Price: 1000, + } + + createdReview := &entities.ReviewModels{ + ID: 1, + UserID: reviewData.UserID, + ProductID: reviewData.ProductID, + Rating: reviewData.Rating, + Description: reviewData.Description, + Date: reviewData.Date, + CreatedAt: reviewData.CreatedAt, + } + + t.Run("Success Case - Create Review", func(t *testing.T) { + productServiceMock.On("GetProductByID", reviewData.ProductID).Return(product, nil) + reviewService.(*ReviewService).productService = productServiceMock + + repo.On("CreateReview", mock.AnythingOfType("*entities.ReviewModels")).Return(createdReview, nil) + productServiceMock.On("UpdateTotalReview", reviewData.ProductID).Return(nil) + repo.On("CountAverageRating", reviewData.ProductID).Return(4.5, nil) + productServiceMock.On("UpdateProductRating", reviewData.ProductID, 4.5).Return(nil) + result, err := reviewService.CreateReview(reviewData) + + assert.Nil(t, err) + assert.NotNil(t, result) + assert.Equal(t, createdReview, result) + productServiceMock.AssertExpectations(t) + repo.AssertExpectations(t) + }) + + t.Run("ProductNotFound", func(t *testing.T) { + productServiceMock := productsMocks.NewServiceProductInterface(t) + productServiceMock.On("GetProductByID", reviewData.ProductID).Return(nil, errors.New("Product not found")) + reviewService.(*ReviewService).productService = productServiceMock + + _, err := reviewService.CreateReview(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, "produk tidak ditemukan") + productServiceMock.AssertExpectations(t) + }) + + t.Run("InvalidRating", func(t *testing.T) { + reviewData := &entities.ReviewModels{ + UserID: 2, + ProductID: 2, + Rating: 6, + Description: "Great product!", + Date: time.Now(), + CreatedAt: time.Now(), + } + + productServiceMock := productsMocks.NewServiceProductInterface(t) + productServiceMock.On("GetProductByID", reviewData.ProductID).Return(&entities.ProductModels{}, nil) + reviewService.(*ReviewService).productService = productServiceMock + + _, err := reviewService.CreateReview(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, "rating tidak boleh lebih dari 5") + productServiceMock.AssertExpectations(t) + }) + + t.Run("Failed Case - Update Total Reviews", func(t *testing.T) { + reviewData := &entities.ReviewModels{ + UserID: 2, + ProductID: 2, + Rating: 4, + Description: "Great product!", + Date: time.Now(), + CreatedAt: time.Now(), + } + + productServiceMock := productsMocks.NewServiceProductInterface(t) + product := &entities.ProductModels{ + ID: 2, + Name: "Product ABC", + Price: 1000, + } + productServiceMock.On("GetProductByID", reviewData.ProductID).Return(product, nil) + reviewService.(*ReviewService).productService = productServiceMock + + createdReview := &entities.ReviewModels{ + ID: 1, + UserID: reviewData.UserID, + ProductID: reviewData.ProductID, + Rating: reviewData.Rating, + Description: reviewData.Description, + Date: reviewData.Date, + CreatedAt: reviewData.CreatedAt, + } + repo.On("CreateReview", mock.AnythingOfType("*entities.ReviewModels")).Return(createdReview, nil) + productServiceMock.On("UpdateTotalReview", reviewData.ProductID).Return(errors.New("gagal memperbarui total reviews")) + _, err := reviewService.CreateReview(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, "gagal memperbarui total reviews") + + productServiceMock.AssertExpectations(t) + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Count Average Rating", func(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + productServiceMock.On("GetProductByID", reviewData.ProductID).Return(product, nil) + reviewService.(*ReviewService).productService = productServiceMock + repo.On("CreateReview", mock.AnythingOfType("*entities.ReviewModels")).Return(createdReview, nil) + productServiceMock.On("UpdateTotalReview", reviewData.ProductID).Return(nil) + repo.On("CountAverageRating", reviewData.ProductID).Return(0.0, errors.New("gagal menghitung rata-rata rating produk")) + + _, err := reviewService.CreateReview(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, "gagal menghitung rata-rata rating produk") + + productServiceMock.AssertExpectations(t) + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Update Product Rating", func(t *testing.T) { + reviewData := &entities.ReviewModels{ + UserID: 2, + ProductID: 2, + Rating: 4, + Description: "Great product!", + Date: time.Now(), + CreatedAt: time.Now(), + } + + productServiceMock := productsMocks.NewServiceProductInterface(t) + product := &entities.ProductModels{ + ID: 2, + Name: "Product ABC", + Price: 1000, + } + productServiceMock.On("GetProductByID", reviewData.ProductID).Return(product, nil) + reviewService.(*ReviewService).productService = productServiceMock + + createdReview := &entities.ReviewModels{ + ID: 1, + UserID: reviewData.UserID, + ProductID: reviewData.ProductID, + Rating: reviewData.Rating, + Description: reviewData.Description, + Date: reviewData.Date, + CreatedAt: reviewData.CreatedAt, + } + + repo.On("CreateReview", mock.AnythingOfType("*entities.ReviewModels")).Return(createdReview, nil) + productServiceMock.On("UpdateTotalReview", reviewData.ProductID).Return(nil) + repo.On("CountAverageRating", reviewData.ProductID).Return(4.5, nil) + productServiceMock.On("UpdateProductRating", reviewData.ProductID, 4.5).Return(errors.New("gagal memperbarui rating produk")) + + _, err := reviewService.CreateReview(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, "gagal memperbarui rating produk") + + productServiceMock.AssertExpectations(t) + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Create Review", func(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + productServiceMock := productsMocks.NewServiceProductInterface(t) + productServiceMock.On("GetProductByID", reviewData.ProductID).Return(&entities.ProductModels{}, nil) + reviewService.(*ReviewService).productService = productServiceMock + + expectedErr := errors.New("failed to create review") + repo.On("CreateReview", mock.AnythingOfType("*entities.ReviewModels")).Return(nil, expectedErr) + + _, err := reviewService.CreateReview(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, expectedErr.Error()) + productServiceMock.AssertExpectations(t) + repo.AssertExpectations(t) + }) +} + +func TestCreateReviewImages(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + + reviewData := &entities.ReviewPhotoModels{ + ReviewID: 1, + ImageURL: "https://example.com/image.jpg", + CreatedAt: time.Now(), + } + + createdReviewPhoto := &entities.ReviewPhotoModels{ + ReviewID: reviewData.ReviewID, + ImageURL: reviewData.ImageURL, + CreatedAt: reviewData.CreatedAt, + } + + t.Run("Success Case - Create Review Images", func(t *testing.T) { + repo.On("GetReviewsById", reviewData.ReviewID).Return(&entities.ReviewModels{}, nil) + repo.On("CreateReviewImages", mock.AnythingOfType("*entities.ReviewPhotoModels")).Return(createdReviewPhoto, nil) + + result, err := reviewService.CreateReviewImages(reviewData) + + assert.Nil(t, err) + assert.NotNil(t, result) + assert.Equal(t, createdReviewPhoto, result) + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Produk Not Found", func(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + repo.On("GetReviewsById", reviewData.ReviewID).Return(nil, errors.New("produk tidak ditemukan")) + + _, err := reviewService.CreateReviewImages(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, "produk tidak ditemukan") + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Create Review Images", func(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + repo.On("GetReviewsById", reviewData.ReviewID).Return(&entities.ReviewModels{}, nil) + + expectedErr := errors.New("failed to create review images") + repo.On("CreateReviewImages", mock.AnythingOfType("*entities.ReviewPhotoModels")).Return(nil, expectedErr) + + _, err := reviewService.CreateReviewImages(reviewData) + + assert.Error(t, err) + assert.EqualError(t, err, expectedErr.Error()) + repo.AssertExpectations(t) + }) +} + +func TestGetReviewById(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + + reviewID := uint64(1) + review := &entities.ReviewModels{ + ID: reviewID, + UserID: 2, + ProductID: 2, + Rating: 4, + Description: "Great product!", + Date: time.Now(), + CreatedAt: time.Now(), + } + + t.Run("Success Case - Get Review by ID", func(t *testing.T) { + repo.On("GetReviewsById", reviewID).Return(review, nil) + + result, err := reviewService.GetReviewById(reviewID) + + assert.Nil(t, err) + assert.NotNil(t, result) + assert.Equal(t, review, result) + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Review Not Found", func(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + repo.On("GetReviewsById", reviewID).Return(nil, errors.New("reviews tidak di temukan")) + + _, err := reviewService.GetReviewById(reviewID) + + assert.Error(t, err) + assert.EqualError(t, err, "reviews tidak di temukan") + repo.AssertExpectations(t) + }) +} + +func TestCountAverageRating(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + + productID := uint64(1) + averageRating := 4.5 + + t.Run("Success Case - Count Average Rating", func(t *testing.T) { + repo.On("CountAverageRating", productID).Return(averageRating, nil) + + result, err := reviewService.CountAverageRating(productID) + + assert.Nil(t, err) + assert.Equal(t, averageRating, result) + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Count Average Rating", func(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + repo.On("CountAverageRating", productID).Return(0.0, errors.New("gagal menghitung rata - rata rating")) + + _, err := reviewService.CountAverageRating(productID) + + assert.Error(t, err) + assert.EqualError(t, err, "gagal menghitung rata - rata rating") + repo.AssertExpectations(t) + }) +} + +func TestGetReviewsProductByID(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + + productID := uint64(1) + product := &entities.ProductModels{ + ID: productID, + Name: "Product ABC", + Price: 1000, + } + + t.Run("Success Case - Get Reviews by Product ID", func(t *testing.T) { + repo.On("GetReviewsProductByID", productID).Return(product, nil) + + result, err := reviewService.GetReviewsProductByID(productID) + + assert.Nil(t, err) + assert.NotNil(t, result) + assert.Equal(t, product, result) + repo.AssertExpectations(t) + }) + + t.Run("Failed Case - Product Not Found", func(t *testing.T) { + repo, reviewService, _, _ := setupTestService(t) + repo.On("GetReviewsProductByID", productID).Return(nil, errors.New("produk tidak ditemukan")) + + _, err := reviewService.GetReviewsProductByID(productID) + + assert.Error(t, err) + assert.EqualError(t, err, "produk tidak ditemukan") + repo.AssertExpectations(t) + }) +}