package ucca import ( "testing" ) // ============================================================================ // EscalationTrigger Tests // ============================================================================ func TestDetermineEscalationLevel_E0_LowRiskInfoOnly(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityYES, RiskLevel: RiskLevelMINIMAL, RiskScore: 10, TriggeredRules: []TriggeredRule{ {Code: "R-INFO-001", Severity: "INFO", Description: "Informative Regel"}, }, DSFARecommended: false, Art22Risk: false, } level, reason := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE0 { t.Errorf("Expected E0 for low-risk case, got %s", level) } if reason == "" { t.Error("Expected non-empty reason") } } func TestDetermineEscalationLevel_E1_WarnRules(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityCONDITIONAL, RiskLevel: RiskLevelLOW, RiskScore: 25, TriggeredRules: []TriggeredRule{ {Code: "R-WARN-001", Severity: "WARN", Description: "Warnung"}, }, DSFARecommended: false, Art22Risk: false, } level, reason := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE1 { t.Errorf("Expected E1 for WARN rule, got %s", level) } if reason == "" { t.Error("Expected non-empty reason") } } func TestDetermineEscalationLevel_E1_RiskScore20to40(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityCONDITIONAL, RiskLevel: RiskLevelLOW, RiskScore: 35, TriggeredRules: []TriggeredRule{}, DSFARecommended: false, Art22Risk: false, } level, _ := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE1 { t.Errorf("Expected E1 for risk score 35, got %s", level) } } func TestDetermineEscalationLevel_E2_Article9Data(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityCONDITIONAL, RiskLevel: RiskLevelMEDIUM, RiskScore: 45, TriggeredRules: []TriggeredRule{ {Code: "R-002", Severity: "WARN", Description: "Art. 9 Daten"}, }, DSFARecommended: false, Art22Risk: false, } level, reason := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE2 { t.Errorf("Expected E2 for Art. 9 data, got %s", level) } if reason == "" { t.Error("Expected non-empty reason mentioning Art. 9") } } func TestDetermineEscalationLevel_E2_DSFARecommended(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityCONDITIONAL, RiskLevel: RiskLevelMEDIUM, RiskScore: 42, TriggeredRules: []TriggeredRule{}, DSFARecommended: true, Art22Risk: false, } level, reason := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE2 { t.Errorf("Expected E2 for DSFA recommended, got %s", level) } if reason == "" { t.Error("Expected reason to mention DSFA") } } func TestDetermineEscalationLevel_E3_BlockRule(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityNO, RiskLevel: RiskLevelHIGH, RiskScore: 75, TriggeredRules: []TriggeredRule{ {Code: "R-BLOCK-001", Severity: "BLOCK", Description: "Blockierung"}, }, DSFARecommended: true, Art22Risk: false, } level, reason := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE3 { t.Errorf("Expected E3 for BLOCK rule, got %s", level) } if reason == "" { t.Error("Expected reason to mention BLOCK") } } func TestDetermineEscalationLevel_E3_Art22Risk(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityCONDITIONAL, RiskLevel: RiskLevelHIGH, RiskScore: 55, TriggeredRules: []TriggeredRule{}, DSFARecommended: false, Art22Risk: true, } level, reason := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE3 { t.Errorf("Expected E3 for Art. 22 risk, got %s", level) } if reason == "" { t.Error("Expected reason to mention Art. 22") } } func TestDetermineEscalationLevel_E3_HighRiskScore(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ Feasibility: FeasibilityCONDITIONAL, RiskLevel: RiskLevelHIGH, RiskScore: 70, // Above E3 threshold TriggeredRules: []TriggeredRule{}, DSFARecommended: false, Art22Risk: false, } level, _ := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE3 { t.Errorf("Expected E3 for risk score 70, got %s", level) } } // ============================================================================ // SLA Tests // ============================================================================ func TestGetDefaultSLA_E0(t *testing.T) { response, resolution := GetDefaultSLA(EscalationLevelE0) if response != 0 || resolution != 0 { t.Errorf("E0 should have no SLA, got response=%d, resolution=%d", response, resolution) } } func TestGetDefaultSLA_E1(t *testing.T) { response, resolution := GetDefaultSLA(EscalationLevelE1) if response != 24 { t.Errorf("E1 should have 24h response SLA, got %d", response) } if resolution != 72 { t.Errorf("E1 should have 72h resolution SLA, got %d", resolution) } } func TestGetDefaultSLA_E2(t *testing.T) { response, resolution := GetDefaultSLA(EscalationLevelE2) if response != 8 { t.Errorf("E2 should have 8h response SLA, got %d", response) } if resolution != 48 { t.Errorf("E2 should have 48h resolution SLA, got %d", resolution) } } func TestGetDefaultSLA_E3(t *testing.T) { response, resolution := GetDefaultSLA(EscalationLevelE3) if response != 4 { t.Errorf("E3 should have 4h response SLA, got %d", response) } if resolution != 24 { t.Errorf("E3 should have 24h resolution SLA, got %d", resolution) } } // ============================================================================ // Role Assignment Tests // ============================================================================ func TestGetRoleForLevel_E0(t *testing.T) { role := GetRoleForLevel(EscalationLevelE0) if role != "" { t.Errorf("E0 should have no role, got %s", role) } } func TestGetRoleForLevel_E1(t *testing.T) { role := GetRoleForLevel(EscalationLevelE1) if role != "team_lead" { t.Errorf("E1 should require team_lead, got %s", role) } } func TestGetRoleForLevel_E2(t *testing.T) { role := GetRoleForLevel(EscalationLevelE2) if role != "dsb" { t.Errorf("E2 should require dsb, got %s", role) } } func TestGetRoleForLevel_E3(t *testing.T) { role := GetRoleForLevel(EscalationLevelE3) if role != "dsb" { t.Errorf("E3 should require dsb (primary), got %s", role) } } // ============================================================================ // Default Trigger Configuration Tests // ============================================================================ func TestDefaultEscalationTrigger_Thresholds(t *testing.T) { trigger := DefaultEscalationTrigger() if trigger.E1RiskThreshold != 20 { t.Errorf("E1 threshold should be 20, got %d", trigger.E1RiskThreshold) } if trigger.E2RiskThreshold != 40 { t.Errorf("E2 threshold should be 40, got %d", trigger.E2RiskThreshold) } if trigger.E3RiskThreshold != 60 { t.Errorf("E3 threshold should be 60, got %d", trigger.E3RiskThreshold) } } // ============================================================================ // Edge Case Tests // ============================================================================ func TestDetermineEscalationLevel_BoundaryRiskScores(t *testing.T) { trigger := DefaultEscalationTrigger() tests := []struct { name string riskScore int expectedLevel EscalationLevel }{ {"Risk 0 → E0", 0, EscalationLevelE0}, {"Risk 19 → E0", 19, EscalationLevelE0}, {"Risk 20 → E0 (boundary)", 20, EscalationLevelE0}, {"Risk 21 → E1", 21, EscalationLevelE1}, {"Risk 39 → E1", 39, EscalationLevelE1}, {"Risk 40 → E1 (boundary)", 40, EscalationLevelE1}, {"Risk 41 → E2", 41, EscalationLevelE2}, {"Risk 59 → E2", 59, EscalationLevelE2}, {"Risk 60 → E2 (boundary)", 60, EscalationLevelE2}, {"Risk 61 → E3", 61, EscalationLevelE3}, {"Risk 100 → E3", 100, EscalationLevelE3}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := &AssessmentResult{ RiskScore: tt.riskScore, TriggeredRules: []TriggeredRule{}, DSFARecommended: false, Art22Risk: false, } level, _ := trigger.DetermineEscalationLevel(result) if level != tt.expectedLevel { t.Errorf("Expected %s for risk score %d, got %s", tt.expectedLevel, tt.riskScore, level) } }) } } func TestDetermineEscalationLevel_CombinedFactors(t *testing.T) { trigger := DefaultEscalationTrigger() // Multiple E3 factors should still result in E3 result := &AssessmentResult{ RiskScore: 80, TriggeredRules: []TriggeredRule{ {Code: "R-BLOCK-001", Severity: "BLOCK", Description: "Block 1"}, {Code: "R-BLOCK-002", Severity: "BLOCK", Description: "Block 2"}, }, DSFARecommended: true, Art22Risk: true, } level, reason := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE3 { t.Errorf("Expected E3 for multiple high-risk factors, got %s", level) } // Reason should mention multiple factors if reason == "" { t.Error("Expected comprehensive reason for multiple factors") } } func TestDetermineEscalationLevel_EmptyRules(t *testing.T) { trigger := DefaultEscalationTrigger() result := &AssessmentResult{ RiskScore: 5, TriggeredRules: []TriggeredRule{}, DSFARecommended: false, Art22Risk: false, } level, _ := trigger.DetermineEscalationLevel(result) if level != EscalationLevelE0 { t.Errorf("Expected E0 for empty rules and low risk, got %s", level) } } // ============================================================================ // Constants Validation Tests // ============================================================================ func TestEscalationLevelConstants(t *testing.T) { levels := []EscalationLevel{ EscalationLevelE0, EscalationLevelE1, EscalationLevelE2, EscalationLevelE3, } expected := []string{"E0", "E1", "E2", "E3"} for i, level := range levels { if string(level) != expected[i] { t.Errorf("Expected %s, got %s", expected[i], level) } } } func TestEscalationStatusConstants(t *testing.T) { statuses := map[EscalationStatus]string{ EscalationStatusPending: "pending", EscalationStatusAssigned: "assigned", EscalationStatusInReview: "in_review", EscalationStatusApproved: "approved", EscalationStatusRejected: "rejected", EscalationStatusReturned: "returned", } for status, expected := range statuses { if string(status) != expected { t.Errorf("Expected status %s, got %s", expected, status) } } } func TestEscalationDecisionConstants(t *testing.T) { decisions := map[EscalationDecision]string{ EscalationDecisionApprove: "approve", EscalationDecisionReject: "reject", EscalationDecisionModify: "modify", EscalationDecisionEscalate: "escalate", } for decision, expected := range decisions { if string(decision) != expected { t.Errorf("Expected decision %s, got %s", expected, decision) } } } // ============================================================================ // Helper Function Tests // ============================================================================ func TestJoinReasons_Empty(t *testing.T) { result := joinReasons([]string{}, "Prefix: ") if result != "Prefix: " { t.Errorf("Expected 'Prefix: ', got '%s'", result) } } func TestJoinReasons_Single(t *testing.T) { result := joinReasons([]string{"Reason 1"}, "Test: ") if result != "Test: Reason 1" { t.Errorf("Expected 'Test: Reason 1', got '%s'", result) } } func TestJoinReasons_Multiple(t *testing.T) { result := joinReasons([]string{"Reason 1", "Reason 2", "Reason 3"}, "Test: ") expected := "Test: Reason 1; Reason 2; Reason 3" if result != expected { t.Errorf("Expected '%s', got '%s'", expected, result) } }