Files
breakpilot-compliance/ai-compliance-sdk/internal/ucca/pdf_export_test.go
Benjamin Boenisch 4435e7ea0a Initial commit: breakpilot-compliance - Compliance SDK Platform
Services: Admin-Compliance, Backend-Compliance,
AI-Compliance-SDK, Consent-SDK, Developer-Portal,
PCA-Platform, DSMS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:28 +01:00

239 lines
6.6 KiB
Go

package ucca
import (
"encoding/base64"
"strings"
"testing"
"time"
"github.com/google/uuid"
)
func TestPDFExporter_Creation(t *testing.T) {
exporter := NewPDFExporter("de")
if exporter == nil {
t.Error("Expected exporter to be created")
}
// Default language
exporter = NewPDFExporter("")
if exporter.language != "de" {
t.Errorf("Expected default language 'de', got '%s'", exporter.language)
}
}
func TestPDFExporter_ExportMarkdown(t *testing.T) {
overview := createTestOverview()
exporter := NewPDFExporter("de")
response, err := exporter.ExportMarkdown(overview)
if err != nil {
t.Fatalf("Failed to export markdown: %v", err)
}
if response.ContentType != "text/markdown" {
t.Errorf("Expected content type 'text/markdown', got '%s'", response.ContentType)
}
if !strings.HasSuffix(response.Filename, ".md") {
t.Errorf("Expected filename to end with .md, got '%s'", response.Filename)
}
// Check content contains expected sections
if !strings.Contains(response.Content, "# Regulatorische Pflichten-Uebersicht") {
t.Error("Expected markdown to contain title")
}
if !strings.Contains(response.Content, "Executive Summary") {
t.Error("Expected markdown to contain executive summary")
}
if !strings.Contains(response.Content, "Anwendbare Regulierungen") {
t.Error("Expected markdown to contain regulations section")
}
}
func TestPDFExporter_ExportPDF(t *testing.T) {
overview := createTestOverview()
exporter := NewPDFExporter("de")
response, err := exporter.ExportManagementMemo(overview)
if err != nil {
t.Fatalf("Failed to export PDF: %v", err)
}
if response.ContentType != "application/pdf" {
t.Errorf("Expected content type 'application/pdf', got '%s'", response.ContentType)
}
if !strings.HasSuffix(response.Filename, ".pdf") {
t.Errorf("Expected filename to end with .pdf, got '%s'", response.Filename)
}
// Check that content is valid base64
decoded, err := base64.StdEncoding.DecodeString(response.Content)
if err != nil {
t.Fatalf("Failed to decode base64 content: %v", err)
}
// Check PDF magic bytes
if len(decoded) < 4 || string(decoded[:4]) != "%PDF" {
t.Error("Expected content to start with PDF magic bytes")
}
}
func TestPDFExporter_ExportEmptyOverview(t *testing.T) {
overview := &ManagementObligationsOverview{
ID: uuid.New(),
AssessmentDate: time.Now(),
ApplicableRegulations: []ApplicableRegulation{},
Obligations: []Obligation{},
RequiredControls: []ObligationControl{},
IncidentDeadlines: []IncidentDeadline{},
ExecutiveSummary: ExecutiveSummary{
TotalRegulations: 0,
TotalObligations: 0,
ComplianceScore: 100,
KeyRisks: []string{},
RecommendedActions: []string{},
},
SanctionsSummary: SanctionsSummary{
Summary: "Keine Sanktionen identifiziert.",
},
}
exporter := NewPDFExporter("de")
// Test Markdown
mdResponse, err := exporter.ExportMarkdown(overview)
if err != nil {
t.Fatalf("Failed to export empty overview as markdown: %v", err)
}
if mdResponse.Content == "" {
t.Error("Expected non-empty markdown content")
}
// Test PDF
pdfResponse, err := exporter.ExportManagementMemo(overview)
if err != nil {
t.Fatalf("Failed to export empty overview as PDF: %v", err)
}
if pdfResponse.Content == "" {
t.Error("Expected non-empty PDF content")
}
}
func TestPDFExporter_WithIncidentDeadlines(t *testing.T) {
overview := createTestOverview()
overview.IncidentDeadlines = []IncidentDeadline{
{
RegulationID: "nis2",
Phase: "Erstmeldung",
Deadline: "24 Stunden",
Recipient: "BSI",
Content: "Unverzuegliche Meldung erheblicher Sicherheitsvorfaelle",
},
{
RegulationID: "dsgvo",
Phase: "Meldung an Aufsichtsbehoerde",
Deadline: "72 Stunden",
Recipient: "Zustaendige Aufsichtsbehoerde",
Content: "Meldung bei Datenschutzverletzung",
},
}
exporter := NewPDFExporter("de")
// Test that incident deadlines are included
mdResponse, err := exporter.ExportMarkdown(overview)
if err != nil {
t.Fatalf("Failed to export: %v", err)
}
if !strings.Contains(mdResponse.Content, "24 Stunden") {
t.Error("Expected markdown to contain 24 hour deadline")
}
if !strings.Contains(mdResponse.Content, "72 Stunden") {
t.Error("Expected markdown to contain 72 hour deadline")
}
}
func createTestOverview() *ManagementObligationsOverview {
deadline := time.Date(2025, 1, 17, 0, 0, 0, 0, time.UTC)
return &ManagementObligationsOverview{
ID: uuid.New(),
TenantID: uuid.New(),
OrganizationName: "Test GmbH",
AssessmentDate: time.Now(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
ApplicableRegulations: []ApplicableRegulation{
{
ID: "nis2",
Name: "NIS2-Richtlinie",
Classification: "wichtige_einrichtung",
Reason: "Anbieter digitaler Dienste",
ObligationCount: 5,
ControlCount: 3,
},
{
ID: "dsgvo",
Name: "DSGVO",
Classification: "controller",
Reason: "Verarbeitung personenbezogener Daten",
ObligationCount: 4,
ControlCount: 2,
},
},
Obligations: []Obligation{
{
ID: "NIS2-OBL-001",
RegulationID: "nis2",
Title: "BSI-Registrierung",
Description: "Registrierung beim BSI",
LegalBasis: []LegalReference{{Norm: "§ 33 BSIG-E"}},
Category: CategoryMeldepflicht,
Responsible: RoleManagement,
Deadline: &Deadline{Type: DeadlineAbsolute, Date: &deadline},
Sanctions: &SanctionInfo{MaxFine: "500.000 EUR"},
Priority: PriorityCritical,
},
{
ID: "DSGVO-OBL-001",
RegulationID: "dsgvo",
Title: "Verarbeitungsverzeichnis",
Description: "Fuehrung eines VVT",
LegalBasis: []LegalReference{{Norm: "Art. 30 DSGVO"}},
Category: CategoryGovernance,
Responsible: RoleDSB,
Priority: PriorityHigh,
},
},
ExecutiveSummary: ExecutiveSummary{
TotalRegulations: 2,
TotalObligations: 9,
CriticalObligations: 1,
UpcomingDeadlines: 2,
OverdueObligations: 0,
KeyRisks: []string{
"BSI-Registrierung faellig",
"Persoenliche Haftung moeglich",
},
RecommendedActions: []string{
"BSI-Registrierung durchfuehren",
"ISMS aufbauen",
},
ComplianceScore: 75,
},
SanctionsSummary: SanctionsSummary{
MaxFinancialRisk: "10 Mio. EUR oder 2% Jahresumsatz",
PersonalLiabilityRisk: true,
CriminalLiabilityRisk: false,
AffectedRegulations: []string{"nis2", "dsgvo"},
Summary: "Hohe Bussgelder moeglich. Persoenliche Haftung der Geschaeftsfuehrung bei Verstoessen.",
},
}
}