app-cloudep-comment-server/pkg/usecase/comment_test.go

482 lines
12 KiB
Go
Raw Permalink Normal View History

2025-01-15 05:17:30 +00:00
package usecase
import (
"context"
"encoding/base64"
"errors"
2025-01-15 05:25:55 +00:00
"testing"
"time"
2025-01-15 05:46:36 +00:00
"code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/comment"
"code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/entity"
"code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/repository"
"code.30cm.net/digimon/app-cloudep-comment-server/pkg/domain/usecase"
2025-01-15 05:17:30 +00:00
"github.com/golang/snappy"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.uber.org/mock/gomock"
2025-01-15 05:46:36 +00:00
mockRepo "code.30cm.net/digimon/app-cloudep-comment-server/pkg/mock/repository"
err "code.30cm.net/digimon/app-cloudep-comment-server/pkg/repository"
2025-01-15 05:17:30 +00:00
)
func TestCommentUseCase_CreateCommentItem(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockCommentRepository := mockRepo.NewMockCommentRepository(mockCtrl)
uc := MustCommentUseCase(CommentUseCaseParam{
Comment: mockCommentRepository,
})
tests := []struct {
name string
req usecase.CreateCommentDocs
mockSetup func()
wantErr bool
}{
{
name: "successfully create top-level comment",
req: usecase.CreateCommentDocs{
UID: "user-123",
ReferenceID: "ref-001",
Message: "This is a top-level comment",
},
mockSetup: func() {
mockCommentRepository.EXPECT().
CreateComment(gomock.Any(), gomock.Any()).
DoAndReturn(func(ctx context.Context, e *entity.Comments) error {
// 驗證插入內容是否正確
assert.Equal(t, "user-123", e.UID)
assert.Equal(t, "ref-001", e.ReferenceID)
assert.Equal(t, comment.TopLevelComment, e.Level)
return nil
})
},
wantErr: false,
},
{
name: "successfully create sub-level comment",
req: usecase.CreateCommentDocs{
UID: "user-456",
ReferenceID: "ref-002",
ParentCommentID: "parent-001",
Message: "This is a sub-level comment",
},
mockSetup: func() {
mockCommentRepository.EXPECT().
CreateComment(gomock.Any(), gomock.Any()).
DoAndReturn(func(ctx context.Context, e *entity.Comments) error {
// 驗證插入內容是否正確
assert.Equal(t, "user-456", e.UID)
assert.Equal(t, "ref-002", e.ReferenceID)
assert.Equal(t, "parent-001", e.ParentCommentID)
assert.Equal(t, comment.SubLevelComment, e.Level)
return nil
})
},
wantErr: false,
},
{
name: "failed to create comment due to repository error",
req: usecase.CreateCommentDocs{
UID: "user-789",
ReferenceID: "ref-003",
Message: "This is a failing comment",
},
mockSetup: func() {
mockCommentRepository.EXPECT().
CreateComment(gomock.Any(), gomock.Any()).
Return(errors.New("database error"))
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.mockSetup()
err := uc.CreateCommentItem(context.Background(), tt.req)
if tt.wantErr {
assert.Error(t, err)
if err != nil {
assert.Contains(t, err.Error(), "failed to create comment")
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestCommentUseCase_GetCommentItem(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockCommentRepository := mockRepo.NewMockCommentRepository(mockCtrl)
uc := MustCommentUseCase(CommentUseCaseParam{
Comment: mockCommentRepository,
})
tests := []struct {
name string
id string
mockSetup func()
wantErr bool
expected *usecase.CommentDocs
}{
{
name: "successfully get comment item",
id: "64a1f2e9347e1a001d345678",
mockSetup: func() {
mockCommentRepository.EXPECT().
ListComments(gomock.Any(), gomock.Any()).
DoAndReturn(func(ctx context.Context, req repository.ListCommentRequest) ([]*entity.Comments, int64, error) {
assert.Equal(t, "64a1f2e9347e1a001d345678", *req.ReferenceID)
return []*entity.Comments{
{
ID: primitive.NewObjectID(),
UID: "user-123",
ReferenceID: "64a1f2e9347e1a001d345678",
ParentCommentID: "",
Message: base64.StdEncoding.EncodeToString(snappy.Encode(nil, []byte("This is a test comment"))),
UpdatedAt: time.Now().UTC().UnixNano(),
CreatedAt: time.Now().UTC().UnixNano(),
},
}, 1, nil
})
},
wantErr: false,
expected: &usecase.CommentDocs{
UID: "user-123",
ReferenceID: "64a1f2e9347e1a001d345678",
ParentCommentID: "",
Message: "This is a test comment",
},
},
{
name: "comment not found",
id: "64a1f2e9347e1a001d345679",
mockSetup: func() {
mockCommentRepository.EXPECT().
ListComments(gomock.Any(), gomock.Any()).
Return([]*entity.Comments{}, int64(0), err.ErrNotFound)
},
wantErr: true,
},
{
name: "database error",
id: "64a1f2e9347e1a001d345680",
mockSetup: func() {
mockCommentRepository.EXPECT().
ListComments(gomock.Any(), gomock.Any()).
Return([]*entity.Comments{}, int64(0), errors.New("database error"))
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.mockSetup()
comment, err := uc.GetCommentItem(context.Background(), tt.id)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.NotNil(t, comment)
assert.Equal(t, tt.expected.UID, comment.UID)
assert.Equal(t, tt.expected.ReferenceID, comment.ReferenceID)
assert.Equal(t, tt.expected.Message, comment.Message)
assert.Equal(t, tt.expected.ParentCommentID, comment.ParentCommentID)
}
})
}
}
func TestCommentUseCase_UpdateCommentMessage(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
// Mock Repository
mockCommentRepository := mockRepo.NewMockCommentRepository(mockCtrl)
// UseCase Initialization
uc := MustCommentUseCase(CommentUseCaseParam{
Comment: mockCommentRepository,
})
tests := []struct {
name string
id string
message string
mockSetup func()
wantErr bool
}{
{
name: "successfully update comment message",
id: "64a1f2e9347e1a001d345678", // Valid ObjectID
message: "Updated comment message",
mockSetup: func() {
mockCommentRepository.EXPECT().
UpdateCommentMessage(gomock.Any(), "64a1f2e9347e1a001d345678", "Updated comment message").
Return(nil)
},
wantErr: false,
},
{
name: "invalid ObjectID format",
id: "invalid-id", // Invalid ObjectID
message: "Invalid ID test",
mockSetup: func() {
mockCommentRepository.EXPECT().
UpdateCommentMessage(gomock.Any(), "invalid-id", "Invalid ID test").
Return(err.ErrInvalidObjectID)
},
wantErr: true,
},
{
name: "comment not found",
id: "64a1f2e9347e1a001d345679", // Non-existent ObjectID
message: "Non-existent comment",
mockSetup: func() {
mockCommentRepository.EXPECT().
UpdateCommentMessage(gomock.Any(), "64a1f2e9347e1a001d345679", "Non-existent comment").
Return(err.ErrNotFound)
},
wantErr: true,
},
{
name: "database error while updating",
id: "64a1f2e9347e1a001d345680",
message: "Database error test",
mockSetup: func() {
mockCommentRepository.EXPECT().
UpdateCommentMessage(gomock.Any(), "64a1f2e9347e1a001d345680", "Database error test").
Return(errors.New("database error"))
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Mock Setup
tt.mockSetup()
// Execute UseCase
err := uc.UpdateCommentMessage(context.Background(), tt.id, tt.message)
// Assert Results
if tt.wantErr {
assert.Error(t, err)
if err != nil {
assert.Contains(t, err.Error(), "failed to update comment")
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestCommentUseCase_RemoveCommentItem(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
// Mock Repository
mockCommentRepository := mockRepo.NewMockCommentRepository(mockCtrl)
// UseCase Initialization
uc := MustCommentUseCase(CommentUseCaseParam{
Comment: mockCommentRepository,
})
tests := []struct {
name string
id string
mockSetup func()
wantErr bool
}{
{
name: "successfully remove comment item",
id: "64a1f2e9347e1a001d345678", // Valid ObjectID
mockSetup: func() {
mockCommentRepository.EXPECT().
DeleteCommentByID(gomock.Any(), "64a1f2e9347e1a001d345678").
Return(nil)
},
wantErr: false,
},
{
name: "invalid ObjectID format",
id: "invalid-id", // Invalid ObjectID
mockSetup: func() {
mockCommentRepository.EXPECT().
DeleteCommentByID(gomock.Any(), "invalid-id").
Return(err.ErrInvalidObjectID)
},
wantErr: true,
},
{
name: "comment not found",
id: "64a1f2e9347e1a001d345679", // Non-existent ObjectID
mockSetup: func() {
mockCommentRepository.EXPECT().
DeleteCommentByID(gomock.Any(), "64a1f2e9347e1a001d345679").
Return(err.ErrNotFound)
},
wantErr: true,
},
{
name: "database error while deleting",
id: "64a1f2e9347e1a001d345680",
mockSetup: func() {
mockCommentRepository.EXPECT().
DeleteCommentByID(gomock.Any(), "64a1f2e9347e1a001d345680").
Return(errors.New("database error"))
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Mock Setup
tt.mockSetup()
// Execute UseCase
err := uc.RemoveCommentItem(context.Background(), tt.id)
// Assert Results
if tt.wantErr {
assert.Error(t, err)
if err != nil {
assert.Contains(t, err.Error(), "failed to del comment")
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestCommentUseCase_ListComment(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
// Mock Repository
mockCommentRepository := mockRepo.NewMockCommentRepository(mockCtrl)
// UseCase Initialization
uc := MustCommentUseCase(CommentUseCaseParam{
Comment: mockCommentRepository,
})
tests := []struct {
name string
req usecase.ListCommentRequest
mockSetup func()
wantErr bool
expected []*usecase.CommentDocs
total int64
}{
{
name: "successfully list comments with replies",
req: usecase.ListCommentRequest{
PageSize: 10,
PageIndex: 1,
},
mockSetup: func() {
// Mock main layer comments
mockCommentRepository.EXPECT().
ListComments(gomock.Any(), gomock.Any()).
Return([]*entity.Comments{
{
ID: primitive.NewObjectID(),
UID: "user-123",
ReferenceID: "ref-001",
Message: base64.StdEncoding.EncodeToString(snappy.Encode(nil, []byte("Comment 1"))),
UpdatedAt: time.Now().UnixNano(),
CreatedAt: time.Now().UnixNano(),
},
}, int64(1), nil)
// Mock replies
mockCommentRepository.EXPECT().
ListComments(gomock.Any(), gomock.Any()).
Return([]*entity.Comments{
{
ID: primitive.NewObjectID(),
UID: "user-456",
ReferenceID: "ref-001",
ParentCommentID: "parent-001",
Message: base64.StdEncoding.EncodeToString(snappy.Encode(nil, []byte("Reply 1"))),
UpdatedAt: time.Now().UnixNano(),
CreatedAt: time.Now().UnixNano(),
},
}, int64(1), nil)
},
wantErr: false,
expected: []*usecase.CommentDocs{
{
UID: "user-123",
ReferenceID: "ref-001",
Message: "Comment 1",
Replies: []*usecase.CommentDocs{
{
UID: "user-456",
ReferenceID: "ref-001",
ParentCommentID: "parent-001",
Message: "Reply 1",
},
},
},
},
total: 1,
},
{
name: "database error while listing comments",
req: usecase.ListCommentRequest{
PageSize: 10,
PageIndex: 1,
},
mockSetup: func() {
mockCommentRepository.EXPECT().
ListComments(gomock.Any(), gomock.Any()).
Return([]*entity.Comments{}, int64(0), errors.New("database error"))
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Mock Setup
tt.mockSetup()
// Execute UseCase
results, total, err := uc.ListComment(context.Background(), tt.req)
// Assert Results
if tt.wantErr {
assert.Error(t, err)
assert.Nil(t, results)
assert.Equal(t, int64(0), total)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.total, total)
assert.Len(t, results, len(tt.expected))
for i, expectedComment := range tt.expected {
assert.Equal(t, expectedComment.Message, results[i].Message)
}
}
})
}
}