| 505 | } |
| 506 | |
| 507 | func TestTaskSemanticValidation(t *testing.T) { |
| 508 | t.Parallel() |
| 509 | |
| 510 | tests := []struct { |
| 511 | name string |
| 512 | run func() error |
| 513 | wantErr error |
| 514 | }{ |
| 515 | { |
| 516 | name: "draft task cannot be closed", |
| 517 | run: func() error { |
| 518 | taskRecord := validTask() |
| 519 | taskRecord.Status = TaskStatusDraft |
| 520 | taskRecord.ClosedAt = time.Date(2026, 4, 14, 12, 45, 0, 0, time.UTC) |
| 521 | return taskRecord.Validate() |
| 522 | }, |
| 523 | wantErr: ErrValidation, |
| 524 | }, |
| 525 | { |
| 526 | name: "task invalid priority", |
| 527 | run: func() error { |
| 528 | taskRecord := validTask() |
| 529 | taskRecord.Priority = Priority("p0") |
| 530 | return taskRecord.Validate() |
| 531 | }, |
| 532 | wantErr: ErrValidation, |
| 533 | }, |
| 534 | { |
| 535 | name: "task invalid max attempts", |
| 536 | run: func() error { |
| 537 | taskRecord := validTask() |
| 538 | taskRecord.MaxAttempts = -1 |
| 539 | return taskRecord.Validate() |
| 540 | }, |
| 541 | wantErr: ErrValidation, |
| 542 | }, |
| 543 | { |
| 544 | name: "task manual approval pending valid", |
| 545 | run: func() error { |
| 546 | taskRecord := validTask() |
| 547 | taskRecord.ApprovalPolicy = ApprovalPolicyManual |
| 548 | taskRecord.ApprovalState = ApprovalStatePending |
| 549 | return taskRecord.Validate() |
| 550 | }, |
| 551 | }, |
| 552 | { |
| 553 | name: "task no-approval with pending state invalid", |
| 554 | run: func() error { |
| 555 | taskRecord := validTask() |
| 556 | taskRecord.ApprovalState = ApprovalStatePending |
| 557 | return taskRecord.Validate() |
| 558 | }, |
| 559 | wantErr: ErrValidation, |
| 560 | }, |
| 561 | { |
| 562 | name: "task manual approval with not-required state invalid", |
| 563 | run: func() error { |
| 564 | taskRecord := validTask() |