Empty assigned heal now clears only exited or non-member reviewer/approver holders and never blanks author. Explicit reconcile uses the pre-update duty plus a project advisory lock so viewer demotion and transfers are not left to generic heal. Co-authored-by: Cursor <cursoragent@cursor.com>
63 lines
2.0 KiB
Go
63 lines
2.0 KiB
Go
package docduty
|
|
|
|
import "testing"
|
|
|
|
func TestPlanSlotRevocations_ReviewerToViewer(t *testing.T) {
|
|
got := PlanSlotRevocations(MemberDutyChange{
|
|
UserID: 171, PreviousDuty: DutyReviewer, NextDuty: DutyNone,
|
|
})
|
|
if len(got) != 1 || got[0].UserID != 171 || got[0].Duty != DutyReviewer {
|
|
t.Fatalf("reviewer→viewer: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestPlanSlotRevocations_DutyTransfer(t *testing.T) {
|
|
got := PlanSlotRevocations(MemberDutyChange{
|
|
UserID: 99, PreviousDuty: DutyNone, NextDuty: DutyReviewer,
|
|
PriorHolderIDs: map[string]int64{DutyReviewer: 171},
|
|
})
|
|
if len(got) != 1 || got[0].UserID != 171 || got[0].Duty != DutyReviewer {
|
|
t.Fatalf("transfer must revoke prior reviewer: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestPlanSlotRevocations_ExitedMember(t *testing.T) {
|
|
got := PlanSlotRevocations(MemberDutyChange{
|
|
UserID: 171, PreviousDuty: DutyReviewer, NextDuty: DutyReviewer, Exited: true,
|
|
})
|
|
if len(got) != 1 || got[0].Duty != DutyReviewer {
|
|
t.Fatalf("exited reviewer must revoke: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestPlanSlotRevocations_IdempotentEmpty(t *testing.T) {
|
|
got := PlanSlotRevocations(MemberDutyChange{UserID: 171, PreviousDuty: DutyNone, NextDuty: DutyNone})
|
|
if len(got) != 0 {
|
|
t.Fatalf("repeat empty change must be no-op: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestPlanSlotRevocations_NeverRevokesAuthor(t *testing.T) {
|
|
got := PlanSlotRevocations(MemberDutyChange{
|
|
UserID: 170, PreviousDuty: DutyAuthor, NextDuty: DutyNone,
|
|
PriorHolderIDs: map[string]int64{DutyAuthor: 170},
|
|
})
|
|
if len(got) != 0 {
|
|
t.Fatalf("author must not be revoked: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestPriorDutyHolders_IgnoresExited(t *testing.T) {
|
|
holders := PriorDutyHolders([]Member{
|
|
{UserID: 170, Status: StatusActive, DocumentDuty: DutyAuthor},
|
|
{UserID: 171, Status: "exited", DocumentDuty: DutyReviewer},
|
|
{UserID: 4, Status: StatusActive, DocumentDuty: DutyApprover},
|
|
})
|
|
if holders[DutyAuthor] != 170 || holders[DutyApprover] != 4 {
|
|
t.Fatalf("holders=%v", holders)
|
|
}
|
|
if _, ok := holders[DutyReviewer]; ok {
|
|
t.Fatal("exited reviewer must not be a prior holder")
|
|
}
|
|
}
|