Files
breakpilot-compliance/ai-compliance-sdk/internal/ucca/obligation_condition_engine_test.go
Benjamin Admin 38e278ee3c
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 32s
CI / test-python-backend-compliance (push) Successful in 29s
CI / test-python-document-crawler (push) Successful in 20s
CI / test-python-dsms-gateway (push) Successful in 18s
feat(ucca): Pflichtendatenbank v2 (325 Obligations), Trigger-Engine, TOM-Control-Mapping
- 9 Regulation-JSON-Dateien (DSGVO 80, AI Act 60, NIS2 40, BDSG 30, TTDSG 20, DSA 35, Data Act 25, EU-Maschinen 15, DORA 20)
- Condition-Tree-Engine fuer automatische Pflichtenselektion (all_of/any_of, 80+ Field-Paths)
- Generischer JSONRegulationModule-Loader mit YAML-Fallback
- Bidirektionales TOM-Control-Mapping (291 Obligation→Control, 92 Control→Obligation)
- Gap-Analyse-Engine (Compliance-%, Priority Actions, Domain Breakdown)
- ScopeDecision→UnifiedFacts Bridge fuer Auto-Profiling
- 4 neue API-Endpoints (assess-from-scope, tom-controls, gap-analysis, reverse-lookup)
- Frontend: Auto-Profiling Button, Regulation-Filter Chips, TOM-Panel, Gap-Analyse-View
- 18 Unit Tests (Condition Engine, v2 Loader, TOM Mapper)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:51:44 +01:00

177 lines
4.1 KiB
Go

package ucca
import (
"testing"
)
func TestConditionEngine_NilNode(t *testing.T) {
engine := NewObligationConditionEngine()
facts := NewUnifiedFacts()
if !engine.Evaluate(nil, facts) {
t.Error("nil node should return true (always applies)")
}
}
func TestConditionEngine_LeafEquals(t *testing.T) {
engine := NewObligationConditionEngine()
tests := []struct {
name string
field string
value interface{}
facts func() *UnifiedFacts
expected bool
}{
{
name: "is_controller true",
field: "data_protection.is_controller", value: true,
facts: func() *UnifiedFacts {
f := NewUnifiedFacts()
f.DataProtection.IsController = true
return f
},
expected: true,
},
{
name: "is_controller false mismatch",
field: "data_protection.is_controller", value: true,
facts: func() *UnifiedFacts { return NewUnifiedFacts() },
expected: false,
},
{
name: "employee_count equals",
field: "organization.employee_count", value: float64(50),
facts: func() *UnifiedFacts {
f := NewUnifiedFacts()
f.Organization.EmployeeCount = 50
return f
},
expected: true,
},
{
name: "uses_ai true",
field: "ai_usage.uses_ai", value: true,
facts: func() *UnifiedFacts {
f := NewUnifiedFacts()
f.AIUsage.UsesAI = true
return f
},
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
node := &ConditionNode{
Field: tt.field,
Operator: "EQUALS",
Value: tt.value,
}
result := engine.Evaluate(node, tt.facts())
if result != tt.expected {
t.Errorf("expected %v, got %v", tt.expected, result)
}
})
}
}
func TestConditionEngine_GreaterThan(t *testing.T) {
engine := NewObligationConditionEngine()
facts := NewUnifiedFacts()
facts.Organization.EmployeeCount = 50
node := &ConditionNode{
Field: "organization.employee_count",
Operator: "GREATER_THAN",
Value: float64(19),
}
if !engine.Evaluate(node, facts) {
t.Error("50 > 19 should be true")
}
facts.Organization.EmployeeCount = 10
if engine.Evaluate(node, facts) {
t.Error("10 > 19 should be false")
}
}
func TestConditionEngine_AllOf(t *testing.T) {
engine := NewObligationConditionEngine()
facts := NewUnifiedFacts()
facts.DataProtection.IsController = true
facts.DataProtection.ProcessesSpecialCategories = true
node := &ConditionNode{
AllOf: []ConditionNode{
{Field: "data_protection.is_controller", Operator: "EQUALS", Value: true},
{Field: "data_protection.processes_special_categories", Operator: "EQUALS", Value: true},
},
}
if !engine.Evaluate(node, facts) {
t.Error("all_of with both true should be true")
}
facts.DataProtection.ProcessesSpecialCategories = false
if engine.Evaluate(node, facts) {
t.Error("all_of with one false should be false")
}
}
func TestConditionEngine_AnyOf(t *testing.T) {
engine := NewObligationConditionEngine()
facts := NewUnifiedFacts()
facts.DataProtection.RequiresDSBByLaw = false
node := &ConditionNode{
AnyOf: []ConditionNode{
{Field: "data_protection.needs_dpo", Operator: "EQUALS", Value: true},
{Field: "organization.employee_count", Operator: "GREATER_THAN", Value: float64(19)},
},
}
if engine.Evaluate(node, facts) {
t.Error("any_of with both false should be false")
}
facts.Organization.EmployeeCount = 25
if !engine.Evaluate(node, facts) {
t.Error("any_of with one true should be true")
}
}
func TestConditionEngine_UnknownField(t *testing.T) {
engine := NewObligationConditionEngine()
facts := NewUnifiedFacts()
node := &ConditionNode{
Field: "nonexistent.field",
Operator: "EQUALS",
Value: true,
}
if engine.Evaluate(node, facts) {
t.Error("unknown field should return false")
}
}
func TestConditionEngine_NotEquals(t *testing.T) {
engine := NewObligationConditionEngine()
facts := NewUnifiedFacts()
facts.Organization.Country = "DE"
node := &ConditionNode{
Field: "organization.country",
Operator: "NOT_EQUALS",
Value: "US",
}
if !engine.Evaluate(node, facts) {
t.Error("DE != US should be true")
}
node.Value = "DE"
if engine.Evaluate(node, facts) {
t.Error("DE != DE should be false")
}
}