diff --git a/Makefile b/Makefile index 7d38b0b..aa50acf 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ help: @echo " build Build the application" @echo " clean Clean generated files" @echo " test Run all tests" + @echo " swag Generate swagger docs" @echo " help Show this help message" # 运行应用 @@ -30,4 +31,9 @@ clean: # 运行所有测试 .PHONY: test test: - go test --count=1 ./... \ No newline at end of file + go test --count=1 ./... + +# 生成swagger文档 +.PHONY: swag +swag: + swag init \ No newline at end of file diff --git a/internal/infra/repository/plan_repository.go b/internal/infra/repository/plan_repository.go index c78b8ef..c8c544c 100644 --- a/internal/infra/repository/plan_repository.go +++ b/internal/infra/repository/plan_repository.go @@ -387,7 +387,7 @@ func (r *gormPlanRepository) DeletePlan(id uint) error { switch plan.ContentType { case models.PlanContentTypeTasks: // 删除与此计划关联的所有非子任务 - if err := tx.Where("plan_id = ? AND parent_task_id IS NULL", id).Delete(&models.Task{}).Error; err != nil { + if err := tx.Where("plan_id = ?", id).Delete(&models.Task{}).Error; err != nil { return fmt.Errorf("删除计划ID %d 的任务失败: %w", id, err) } case models.PlanContentTypeSubPlans: diff --git a/internal/infra/repository/plan_repository_test.go b/internal/infra/repository/plan_repository_test.go index abcb2e1..3055b60 100644 --- a/internal/infra/repository/plan_repository_test.go +++ b/internal/infra/repository/plan_repository_test.go @@ -1279,7 +1279,7 @@ func TestPlanRepository_Create(t *testing.T) { tc.setupDB(db) // 执行 Create 操作 - err := repo.Create(tc.inputPlan) + err := repo.CreatePlan(tc.inputPlan) // 断言错误 if tc.expectedError != nil { @@ -1295,3 +1295,131 @@ func TestPlanRepository_Create(t *testing.T) { }) } } + +func TestPlanRepository_DeletePlan(t *testing.T) { + type testCase struct { + name string + setupDB func(db *gorm.DB) (planToDeleteID uint) + expectedError string + verifyDB func(t *testing.T, db *gorm.DB, planToDeleteID uint) + } + + testCases := []testCase{ + { + name: "成功删除-包含任务的计划", + setupDB: func(db *gorm.DB) uint { + plan := models.Plan{Name: "Plan with Tasks", ContentType: models.PlanContentTypeTasks} + db.Create(&plan) + db.Create(&models.Task{PlanID: plan.ID, Name: "Task 1"}) + db.Create(&models.Task{PlanID: plan.ID, Name: "Task 2"}) + return plan.ID + }, + expectedError: "", + verifyDB: func(t *testing.T, db *gorm.DB, planToDeleteID uint) { + var plan models.Plan + err := db.First(&plan, planToDeleteID).Error + assert.Error(t, err) + assert.True(t, errors.Is(err, gorm.ErrRecordNotFound), "计划应被删除") + + var taskCount int64 + db.Model(&models.Task{}).Where("plan_id = ?", planToDeleteID).Count(&taskCount) + assert.Equal(t, int64(0), taskCount, "关联任务应被删除") + }, + }, + { + name: "成功删除-包含子计划链接的计划", + setupDB: func(db *gorm.DB) uint { + parentPlan := models.Plan{Name: "Parent Plan", ContentType: models.PlanContentTypeSubPlans} + childPlan := models.Plan{Name: "Child Plan", ContentType: models.PlanContentTypeTasks} + db.Create(&parentPlan) + db.Create(&childPlan) + db.Create(&models.SubPlan{ParentPlanID: parentPlan.ID, ChildPlanID: childPlan.ID}) + return parentPlan.ID + }, + expectedError: "", + verifyDB: func(t *testing.T, db *gorm.DB, planToDeleteID uint) { + var parentPlan models.Plan + err := db.First(&parentPlan, planToDeleteID).Error + assert.Error(t, err) + assert.True(t, errors.Is(err, gorm.ErrRecordNotFound), "父计划应被删除") + + var subPlanLinkCount int64 + db.Model(&models.SubPlan{}).Where("parent_plan_id = ?", planToDeleteID).Count(&subPlanLinkCount) + assert.Equal(t, int64(0), subPlanLinkCount, "子计划链接应被删除") + + // 验证子计划本身未被删除 + var childPlan models.Plan + err = db.First(&childPlan, 2).Error // Assuming childPlan.ID is 2 from setup + assert.NoError(t, err, "子计划本身不应被删除") + }, + }, + { + name: "失败删除-作为子计划的计划", + setupDB: func(db *gorm.DB) uint { + parentPlan := models.Plan{Name: "Parent Plan", ContentType: models.PlanContentTypeSubPlans} + childPlan := models.Plan{Name: "Child Plan", ContentType: models.PlanContentTypeTasks} + db.Create(&parentPlan) + db.Create(&childPlan) + db.Create(&models.SubPlan{ParentPlanID: parentPlan.ID, ChildPlanID: childPlan.ID}) + return childPlan.ID // 尝试删除子计划 + }, + expectedError: repository.ErrDeleteWithReferencedPlan.Error(), + verifyDB: func(t *testing.T, db *gorm.DB, planToDeleteID uint) { + var childPlan models.Plan + err := db.First(&childPlan, planToDeleteID).Error + assert.NoError(t, err, "子计划不应被删除") + + var subPlanLinkCount int64 + db.Model(&models.SubPlan{}).Where("child_plan_id = ?", planToDeleteID).Count(&subPlanLinkCount) + assert.Equal(t, int64(1), subPlanLinkCount, "子计划链接不应被删除") + }, + }, + { + name: "失败删除-不存在的计划", + setupDB: func(db *gorm.DB) uint { + return 999 // 不存在的ID + }, + expectedError: "record not found", + verifyDB: func(t *testing.T, db *gorm.DB, planToDeleteID uint) { + // 数据库状态应保持不变 + }, + }, + { + name: "成功删除-不含任何关联的计划", + setupDB: func(db *gorm.DB) uint { + plan := models.Plan{Name: "Simple Plan", ContentType: models.PlanContentTypeTasks} + db.Create(&plan) + return plan.ID + }, + expectedError: "", + verifyDB: func(t *testing.T, db *gorm.DB, planToDeleteID uint) { + var plan models.Plan + err := db.First(&plan, planToDeleteID).Error + assert.Error(t, err) + assert.True(t, errors.Is(err, gorm.ErrRecordNotFound), "计划应被删除") + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + db := setupTestDB(t) + sqlDB, _ := db.DB() + defer sqlDB.Close() + + planToDeleteID := tc.setupDB(db) + + repo := repository.NewGormPlanRepository(db) + err := repo.DeletePlan(planToDeleteID) + + if tc.expectedError != "" { + assert.Error(t, err) + assert.Contains(t, err.Error(), tc.expectedError) + } else { + assert.NoError(t, err) + } + + tc.verifyDB(t, db, planToDeleteID) + }) + } +}