Files
backend_v2/internal/service/review_street_group_test.go
toom1996 42f6316125 update
2026-09-25 11:31:52 +08:00

160 lines
5.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"context"
"errors"
"testing"
"fashionapi/internal/dto"
"fashionapi/internal/model"
"fashionapi/internal/pkg/imgurl"
"fashionapi/internal/repository"
)
// fakeGroupRepo 只实现分组相关的仓储方法,其余由嵌入的接口兜底(测试中不会调到未实现的方法)。
type fakeGroupRepo struct {
repository.ReviewRepository
images []model.StreetSnapImage
detail *model.StreetSnap
attachFn func(snapID, mainID uint32, imgIDs []uint32) error
attachRunwayFn func(runwayID, mainID uint32, imgIDs []uint32) error
}
func (f *fakeGroupRepo) StreetRecordDetail(_ context.Context, _ uint32) (*model.StreetSnap, error) {
return f.detail, nil
}
func (f *fakeGroupRepo) StreetRecordImages(_ context.Context, _ uint32) ([]model.StreetSnapImage, error) {
return f.images, nil
}
func (f *fakeGroupRepo) AttachStreetSnapImages(_ context.Context, snapID, mainID uint32, imgIDs []uint32) error {
if f.attachFn != nil {
return f.attachFn(snapID, mainID, imgIDs)
}
return nil
}
func (f *fakeGroupRepo) DetachStreetSnapImage(_ context.Context, _ uint32, _ uint32) error {
if f.attachFn != nil {
return f.attachFn(0, 0, nil)
}
return nil
}
func (f *fakeGroupRepo) AttachRunwayImages(_ context.Context, runwayID, mainID uint32, imgIDs []uint32) error {
if f.attachRunwayFn != nil {
return f.attachRunwayFn(runwayID, mainID, imgIDs)
}
return nil
}
func (f *fakeGroupRepo) DetachRunwayImage(_ context.Context, _ uint32, _ uint32) error {
return nil
}
var _ repository.ReviewRepository = (*fakeGroupRepo)(nil)
func newGroupService(f *fakeGroupRepo) ReviewService {
return NewReviewService(f, nil, imgurl.New("", "", ""), nil)
}
// TestStreetGroupDetailExposesGrouping 详情必须输出可折叠分组:主图各成一组,副图归入主图。
func TestStreetGroupDetailExposesGrouping(t *testing.T) {
repo := &fakeGroupRepo{
detail: &model.StreetSnap{ID: 7, Title: "T", Year: 2026, City: "Beijing", Status: model.StatusPending},
images: []model.StreetSnapImage{
{ID: 1, Image: "main.jpg", Name: "main", SortOrder: 1, IsDetail: 0, ParentImageID: 0},
{ID: 2, Image: "det.jpg", Name: "det", SortOrder: 2, IsDetail: 1, ParentImageID: 1},
{ID: 3, Image: "solo.jpg", Name: "solo", SortOrder: 3, IsDetail: 0, ParentImageID: 0},
},
}
svc := newGroupService(repo)
v, err := svc.RecordDetail(context.Background(), dto.IngestKindStreet, 7)
if err != nil {
t.Fatalf("RecordDetail 失败: %v", err)
}
if len(v.Images) != 3 {
t.Fatalf("Images 应保留扁平 3 张,实际 %d", len(v.Images))
}
if len(v.Groups) != 2 {
t.Fatalf("Groups 应为 2 组,实际 %d", len(v.Groups))
}
if v.Groups[0].Image.ID != 1 || len(v.Groups[0].Details) != 1 {
t.Fatalf("第 0 组应为 1 张主图 + 1 副图,实际 main=%d details=%d", v.Groups[0].Image.ID, len(v.Groups[0].Details))
}
if v.Groups[0].Image.DetailCount != 1 {
t.Fatalf("主图 DetailCount 应为 1,实际 %d", v.Groups[0].Image.DetailCount)
}
if v.Groups[0].Details[0].ID != 2 {
t.Fatalf("副图应为 id=2,实际 %d", v.Groups[0].Details[0].ID)
}
if v.Groups[1].Image.ID != 3 {
t.Fatalf("第 1 组主图应为 id=3,实际 %d", v.Groups[1].Image.ID)
}
}
// TestStreetGroupAttachDelegates 并入必须透传参数到仓储。
func TestStreetGroupAttachDelegates(t *testing.T) {
var got struct {
snapID uint32
mainID uint32
imgIDs []uint32
}
repo := &fakeGroupRepo{attachFn: func(snapID, mainID uint32, imgIDs []uint32) error {
got.snapID, got.mainID, got.imgIDs = snapID, mainID, imgIDs
return nil
}}
svc := newGroupService(repo)
if err := svc.AttachImages(context.Background(), dto.IngestKindStreet, 7, 1, []uint32{2, 3}); err != nil {
t.Fatalf("AttachImages 失败: %v", err)
}
if got.snapID != 7 || got.mainID != 1 || len(got.imgIDs) != 2 {
t.Fatalf("参数透传错误: snapID=%d mainID=%d imgIDs=%v", got.snapID, got.mainID, got.imgIDs)
}
}
// TestStreetGroupNonStreetRejected 既非 street 也非 runway 的实体类型不允许主副图分组操作。
func TestStreetGroupNonStreetRejected(t *testing.T) {
repo := &fakeGroupRepo{}
svc := newGroupService(repo)
if err := svc.AttachImages(context.Background(), "bogus", 7, 1, []uint32{2}); !errors.Is(err, ErrInvalidImageGroup) {
t.Fatalf("未知实体并入应返回 ErrInvalidImageGroup,实际 %v", err)
}
}
// TestRunwayGroupAttachDelegates 走秀并入必须透传参数到 runway 仓储。
func TestRunwayGroupAttachDelegates(t *testing.T) {
var got struct {
runwayID uint32
mainID uint32
imgIDs []uint32
}
repo := &fakeGroupRepo{attachRunwayFn: func(runwayID, mainID uint32, imgIDs []uint32) error {
got.runwayID, got.mainID, got.imgIDs = runwayID, mainID, imgIDs
return nil
}}
svc := newGroupService(repo)
if err := svc.AttachImages(context.Background(), dto.IngestKindRunway, 9, 4, []uint32{5, 6}); err != nil {
t.Fatalf("Runway AttachImages 失败: %v", err)
}
if got.runwayID != 9 || got.mainID != 4 || len(got.imgIDs) != 2 {
t.Fatalf("参数透传错误: runwayID=%d mainID=%d imgIDs=%v", got.runwayID, got.mainID, got.imgIDs)
}
}
// TestStreetGroupPreventCrossRecord 仓储拦截跨记录主图后,service 翻成中文用户错误。
func TestStreetGroupPreventCrossRecord(t *testing.T) {
repo := &fakeGroupRepo{attachFn: func(_, _ uint32, _ []uint32) error {
return repository.ErrInvalidImageGroup
}}
svc := newGroupService(repo)
err := svc.AttachImages(context.Background(), dto.IngestKindStreet, 7, 1, []uint32{2, 3})
if err == nil {
t.Fatal("跨记录应报错")
}
if err.Error() != "主图无效:它必须属于本条记录、未被删除,且自身是主图" {
t.Fatalf("错误文案不符: %q", err.Error())
}
}