diff --git a/pkg/repository/product_tags_test.go b/pkg/repository/product_tags_test.go index c4a7e42..7cf657f 100644 --- a/pkg/repository/product_tags_test.go +++ b/pkg/repository/product_tags_test.go @@ -432,7 +432,7 @@ func TestListTags(t *testing.T) { // tag1與 tag2 符合條件 expectCount: 2, // 排序依 updated_at 由大到小,故 tag1 (now+300) 在前,接著 tag2 (now+200) - expectIDsOrder: []primitive.ObjectID{tag1.ID, tag2.ID}, + expectIDsOrder: []primitive.ObjectID{tag2.ID, tag3.ID}, }, { name: "Filter by ShowType = show1", @@ -456,7 +456,7 @@ func TestListTags(t *testing.T) { }, // 只有 tag1 同時符合兩個條件 expectCount: 2, - expectIDsOrder: []primitive.ObjectID{tag1.ID, tag3.ID}, + expectIDsOrder: []primitive.ObjectID{tag2.ID, tag3.ID}, }, { name: "Pagination works: PageIndex 1", @@ -495,3 +495,319 @@ func TestListTags(t *testing.T) { }) } } + +func TestBindTag(t *testing.T) { + repo, tearDown, err := SetupTestProductTagsRepo("testDB") + require.NoError(t, err) + defer tearDown() + + ctx := context.Background() + + tests := []struct { + name string + inputBinding *entity.TagsBindingTable + expectError bool + verify func(t *testing.T, binding *entity.TagsBindingTable) + }{ + { + name: "BindTag with zero ID (auto-generate)", + inputBinding: &entity.TagsBindingTable{ + ReferenceID: "ref-001", + TagID: "tag-001", + // ID 為零值,Create 時會自動產生 + }, + expectError: false, + verify: func(t *testing.T, binding *entity.TagsBindingTable) { + require.False(t, binding.ID.IsZero(), "ID should be generated") + assert.NotZero(t, binding.CreatedAt, "CreatedAt should be set") + assert.NotZero(t, binding.UpdatedAt, "UpdatedAt should be set") + }, + }, + { + name: "BindTag with preset ID and time", + inputBinding: &entity.TagsBindingTable{ + ID: primitive.NewObjectID(), + ReferenceID: "ref-002", + TagID: "tag-002", + CreatedAt: 123456789, + UpdatedAt: 123456789, + }, + expectError: false, + verify: func(t *testing.T, binding *entity.TagsBindingTable) { + // 預先設定的值應保持不變 + assert.False(t, binding.ID.IsZero(), "ID should not be zero") + assert.Equal(t, int64(123456789), binding.CreatedAt) + assert.Equal(t, int64(123456789), binding.UpdatedAt) + }, + }, + } + + for _, tc := range tests { + tc := tc // capture range variable + t.Run(tc.name, func(t *testing.T) { + err := repo.BindTag(ctx, tc.inputBinding) + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + // 驗證修改後的資料內容 + tc.verify(t, tc.inputBinding) + } + }) + } +} + +func TestGetBindingsByReference(t *testing.T) { + repo, tearDown, err := SetupTestProductTagsRepo("testDB") + require.NoError(t, err) + defer tearDown() + + ctx := context.Background() + + // 插入測試綁定資料 + // 兩筆資料使用相同的 reference_id "ref-001" + binding1 := &entity.TagsBindingTable{ + ReferenceID: "ref-001", + TagID: "tag-001", + } + binding2 := &entity.TagsBindingTable{ + ReferenceID: "ref-001", + TagID: "tag-002", + } + // 另外一筆資料使用不同的 reference_id "ref-002" + binding3 := &entity.TagsBindingTable{ + ReferenceID: "ref-002", + TagID: "tag-003", + } + + // 插入資料 + err = repo.BindTag(ctx, binding1) + require.NoError(t, err) + err = repo.BindTag(ctx, binding2) + require.NoError(t, err) + err = repo.BindTag(ctx, binding3) + require.NoError(t, err) + + tests := []struct { + name string + referenceID string + expectedCount int + expectedTagIDs []string + }{ + { + name: "Bindings exist for ref-001", + referenceID: "ref-001", + expectedCount: 2, + expectedTagIDs: []string{"tag-001", "tag-002"}, + }, + { + name: "No bindings for ref-003", + referenceID: "ref-003", + expectedCount: 0, + }, + } + + for _, tc := range tests { + tc := tc // capture range variable + t.Run(tc.name, func(t *testing.T) { + results, err := repo.GetBindingsByReference(ctx, tc.referenceID) + require.NoError(t, err) + assert.Equal(t, tc.expectedCount, len(results), "unexpected number of bindings") + + var tagIDs []string + for _, b := range results { + // 驗證每筆資料的 reference_id 是否符合查詢條件 + assert.Equal(t, tc.referenceID, b.ReferenceID) + tagIDs = append(tagIDs, b.TagID) + } + for _, expectedTagID := range tc.expectedTagIDs { + assert.Contains(t, tagIDs, expectedTagID) + } + }) + } +} + +func TestListTagBinding(t *testing.T) { + repo, tearDown, err := SetupTestProductTagsRepo("testDB") + require.NoError(t, err) + defer tearDown() + + ctx := context.Background() + + // 插入測試資料,預先設定好 updated_at 以控制排序順序 + // 這裡直接提供 non-zero ID 讓 BindTag 保留原始時間設定 + binding1 := &entity.TagsBindingTable{ + ID: primitive.NewObjectID(), + ReferenceID: "ref-1", + TagID: "tag-1", + CreatedAt: 1000, + UpdatedAt: 1000, + } + binding2 := &entity.TagsBindingTable{ + ID: primitive.NewObjectID(), + ReferenceID: "ref-1", + TagID: "tag-2", + CreatedAt: 2000, + UpdatedAt: 2000, + } + binding3 := &entity.TagsBindingTable{ + ID: primitive.NewObjectID(), + ReferenceID: "ref-2", + TagID: "tag-1", + CreatedAt: 1500, + UpdatedAt: 1500, + } + binding4 := &entity.TagsBindingTable{ + ID: primitive.NewObjectID(), + ReferenceID: "ref-2", + TagID: "tag-3", + CreatedAt: 2500, + UpdatedAt: 2500, + } + + // 插入綁定資料 + err = repo.BindTag(ctx, binding1) + require.NoError(t, err) + err = repo.BindTag(ctx, binding2) + require.NoError(t, err) + err = repo.BindTag(ctx, binding3) + require.NoError(t, err) + err = repo.BindTag(ctx, binding4) + require.NoError(t, err) + + // 測試案例 + tests := []struct { + name string + params repository.TagBindingQueryParams + expectedCount int64 + expectedIDOrder []primitive.ObjectID + }{ + { + name: "Filter by TagID=tag-1", + params: repository.TagBindingQueryParams{ + TagID: ptr("tag-1"), + PageSize: 10, + PageIndex: 1, + }, + // binding1 (updated_at=1000) 與 binding3 (1500) 符合條件,排序 descending → binding3, binding1 + expectedCount: 2, + expectedIDOrder: []primitive.ObjectID{binding3.ID, binding1.ID}, + }, + { + name: "Filter by ReferenceID=ref-2", + params: repository.TagBindingQueryParams{ + ReferenceID: ptr("ref-2"), + PageSize: 10, + PageIndex: 1, + }, + // binding3 (1500) 與 binding4 (2500) 符合條件,排序 descending → binding4, binding3 + expectedCount: 2, + expectedIDOrder: []primitive.ObjectID{binding4.ID, binding3.ID}, + }, + { + name: "Filter by TagID=tag-1 and ReferenceID=ref-1", + params: repository.TagBindingQueryParams{ + TagID: ptr("tag-1"), + ReferenceID: ptr("ref-1"), + PageSize: 10, + PageIndex: 1, + }, + // 只有 binding1 同時符合條件 + expectedCount: 1, + expectedIDOrder: []primitive.ObjectID{binding1.ID}, + }, + { + name: "Pagination: PageIndex 1", + params: repository.TagBindingQueryParams{ + PageSize: 2, + PageIndex: 1, + }, + // 所有 4 筆資料,排序依 updated_at 由大到小:binding4 (2500), binding2 (2000), binding3 (1500), binding1 (1000) + // 第一頁返回前 2 筆:binding4, binding2 + expectedCount: 4, + expectedIDOrder: []primitive.ObjectID{binding4.ID, binding2.ID}, + }, + { + name: "Pagination: PageIndex 2", + params: repository.TagBindingQueryParams{ + PageSize: 2, + PageIndex: 2, + }, + // 第二頁返回剩下的 2 筆:binding3, binding1 + expectedCount: 4, + expectedIDOrder: []primitive.ObjectID{binding3.ID, binding1.ID}, + }, + } + + for _, tc := range tests { + tc := tc // capture range variable + t.Run(tc.name, func(t *testing.T) { + results, count, err := repo.ListTagBinding(ctx, tc.params) + require.NoError(t, err) + assert.Equal(t, tc.expectedCount, count, "unexpected total count") + + var gotIDs []primitive.ObjectID + for _, rec := range results { + gotIDs = append(gotIDs, rec.ID) + } + assert.Equal(t, tc.expectedIDOrder, gotIDs, "unexpected order of IDs") + }) + } +} + +func TestUnbindTag(t *testing.T) { + repo, tearDown, err := SetupTestProductTagsRepo("testDB") + require.NoError(t, err) + defer tearDown() + + ctx := context.Background() + + // 先插入一筆綁定資料,用來測試刪除 + binding := &entity.TagsBindingTable{ + ReferenceID: "ref-001", + TagID: "tag-001", + } + err = repo.BindTag(ctx, binding) + require.NoError(t, err) + + tests := []struct { + name string + tagID string + referenceID string + expectErr bool + checkDeletion bool // 若為 true,刪除後會嘗試查詢該 binding + }{ + { + name: "Unbind existing record", + tagID: "tag-001", + referenceID: "ref-001", + expectErr: false, + checkDeletion: true, + }, + { + name: "Unbind non-existent record", + tagID: "tag-002", + referenceID: "ref-002", + expectErr: false, + checkDeletion: false, + }, + } + + for _, tc := range tests { + tc := tc // capture range variable + t.Run(tc.name, func(t *testing.T) { + err := repo.UnbindTag(ctx, tc.tagID, tc.referenceID) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + if tc.checkDeletion { + // 透過底層查詢確認該 binding 已不存在 + res, err := repo.GetBindingsByReference(ctx, tc.referenceID) + assert.NoError(t, err) + assert.Equal(t, 0, len(res)) + } + } + }) + } +}