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>
239 lines
6.6 KiB
Go
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.",
|
|
},
|
|
}
|
|
}
|