package iace import "testing" func TestDeltaMatch_NoChange(t *testing.T) { engine := NewPatternEngine() input := MatchInput{ ComponentLibraryIDs: []string{"C001"}, EnergySourceIDs: []string{"EN01"}, } result := engine.DeltaMatch(input, input) if len(result.AddedPatterns) != 0 { t.Errorf("expected 0 added patterns for no change, got %d", len(result.AddedPatterns)) } if len(result.RemovedPatterns) != 0 { t.Errorf("expected 0 removed patterns for no change, got %d", len(result.RemovedPatterns)) } if result.SummaryDE != "Keine Auswirkung — die vorgeschlagene Aenderung veraendert die Risikobeurteilung nicht." { t.Errorf("unexpected summary: %s", result.SummaryDE) } } func TestDeltaMatch_AddComponent(t *testing.T) { engine := NewPatternEngine() current := MatchInput{ ComponentLibraryIDs: []string{"C001"}, EnergySourceIDs: []string{"EN01"}, } proposed := MatchInput{ ComponentLibraryIDs: []string{"C001", "C071"}, // Add SPS (programmable) EnergySourceIDs: []string{"EN01"}, } result := engine.DeltaMatch(current, proposed) if len(result.AddedPatterns) == 0 { t.Error("expected added patterns when adding SPS component") } t.Logf("Adding C071 (SPS): +%d patterns, +%d hazard cats, +%d measures", len(result.AddedPatterns), result.AddedHazardCount, result.AddedMeasureCount) } func TestDeltaMatch_RemoveComponent(t *testing.T) { engine := NewPatternEngine() current := MatchInput{ ComponentLibraryIDs: []string{"C001", "C071"}, EnergySourceIDs: []string{"EN01"}, } proposed := MatchInput{ ComponentLibraryIDs: []string{"C001"}, // Remove SPS EnergySourceIDs: []string{"EN01"}, } result := engine.DeltaMatch(current, proposed) if len(result.RemovedPatterns) == 0 { t.Error("expected removed patterns when removing SPS component") } t.Logf("Removing C071: -%d patterns, -%d hazard cats", len(result.RemovedPatterns), result.RemovedHazardCount) } func TestDeltaMatch_AddState(t *testing.T) { engine := NewPatternEngine() current := MatchInput{ ComponentLibraryIDs: []string{"C001", "C071"}, EnergySourceIDs: []string{"EN01"}, LifecyclePhases: []string{"normal_operation"}, OperationalStates: []string{"automatic_operation"}, HumanRoles: []string{"operator"}, } proposed := MatchInput{ ComponentLibraryIDs: []string{"C001", "C071"}, EnergySourceIDs: []string{"EN01"}, LifecyclePhases: []string{"normal_operation", "maintenance"}, OperationalStates: []string{"automatic_operation", "maintenance"}, HumanRoles: []string{"operator", "maintenance_tech"}, } result := engine.DeltaMatch(current, proposed) t.Logf("Adding maintenance state+role: +%d patterns, +%d hazards, +%d measures", len(result.AddedPatterns), result.AddedHazardCount, result.AddedMeasureCount) // Adding maintenance should bring maintenance-specific patterns if len(result.AddedPatterns) == 0 { t.Error("expected added patterns when adding maintenance state") } } func TestDeltaMatch_AddRole(t *testing.T) { engine := NewPatternEngine() current := MatchInput{ ComponentLibraryIDs: []string{"C001", "C071"}, EnergySourceIDs: []string{"EN01"}, LifecyclePhases: []string{"maintenance"}, OperationalStates: []string{"maintenance"}, HumanRoles: []string{"operator"}, // Only operator } proposed := MatchInput{ ComponentLibraryIDs: []string{"C001", "C071"}, EnergySourceIDs: []string{"EN01"}, LifecyclePhases: []string{"maintenance"}, OperationalStates: []string{"maintenance"}, HumanRoles: []string{"operator", "maintenance_tech"}, // Add maintenance_tech } result := engine.DeltaMatch(current, proposed) t.Logf("Adding maintenance_tech role: +%d patterns", len(result.AddedPatterns)) // maintenance_tech role should unlock maintenance-specific patterns if len(result.AddedPatterns) == 0 { t.Error("expected added patterns when adding maintenance_tech role") } } func TestDeltaMatch_SummaryNotEmpty(t *testing.T) { engine := NewPatternEngine() current := MatchInput{ComponentLibraryIDs: []string{"C001"}, EnergySourceIDs: []string{"EN01"}} proposed := MatchInput{ComponentLibraryIDs: []string{"C001", "C071"}, EnergySourceIDs: []string{"EN01"}} result := engine.DeltaMatch(current, proposed) if result.SummaryDE == "" { t.Error("expected non-empty summary") } t.Logf("Summary: %s", result.SummaryDE) } func TestDeltaMatch_Symmetric(t *testing.T) { engine := NewPatternEngine() a := MatchInput{ComponentLibraryIDs: []string{"C001"}, EnergySourceIDs: []string{"EN01"}} b := MatchInput{ComponentLibraryIDs: []string{"C001", "C071"}, EnergySourceIDs: []string{"EN01"}} forward := engine.DeltaMatch(a, b) backward := engine.DeltaMatch(b, a) if len(forward.AddedPatterns) != len(backward.RemovedPatterns) { t.Errorf("forward added (%d) should equal backward removed (%d)", len(forward.AddedPatterns), len(backward.RemovedPatterns)) } }