Files
archivmail/pkg/mailparser/parser_test.go
T
sysopsandClaude Sonnet 5 075afa005a fix(PROJ-74): Test-/Vet-Signatur-Drift beheben, go build/vet/test wieder grün
archivmail-export nutzte noch die alte storage.New(path string)-Signatur
statt storage.Config (fehlender Keyfile/Compress hätte Rohbytes statt
Klartext-EML exportiert). Toten Self-Assignment-Code in storage.go entfernt.
Testdateien (storage, audit, api, userstore, auth) an aktuelle Signaturen
angeglichen; auth-Tests liefen bisher gegen einen SQLite-Pfad statt Postgres-
DSN und wurden auf das TEST_DATABASE_URL-Schema-Isolationsmuster der übrigen
Pakete umgestellt. api_test.go las den Login-Token noch aus dem JSON-Body
statt aus dem httpOnly-Cookie (Auth-Contract-Drift).

TestParseMissingDate an tatsächliches Verhalten angepasst: der Parser lässt
das Datum bewusst als Zero-Value, der time.Now()-Fallback sitzt in der
Storage-Schicht — damit bleibt nachvollziehbar ob ein Datum aus der Mail
stammt oder vom Archiv gesetzt wurde (GoBD).

Verifiziert auf 192.168.1.132: go build/vet/test ./... komplett grün,
kein Skip (Postgres + Manticore erreichbar).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019j28kGcaJAhBnrYX34hGdt
2026-08-05 14:07:46 +02:00

106 lines
2.7 KiB
Go

package mailparser_test
import (
"os"
"path/filepath"
"strings"
"testing"
"archivmail/pkg/mailparser"
)
func readFixture(t *testing.T, name string) []byte {
t.Helper()
data, err := os.ReadFile(filepath.Join("testdata", name))
if err != nil {
t.Fatalf("readFixture %s: %v", name, err)
}
return data
}
func TestParseSimple(t *testing.T) {
raw := readFixture(t, "simple.eml")
p, err := mailparser.Parse(raw)
if err != nil {
t.Fatalf("Parse: %v", err)
}
if p.From != "alice@example.com" {
t.Errorf("From = %q, want alice@example.com", p.From)
}
if len(p.To) != 2 {
t.Errorf("To: got %d recipients, want 2", len(p.To))
}
if len(p.CC) != 1 {
t.Errorf("CC: got %d, want 1", len(p.CC))
}
if p.Subject != "Test Invoice Q1-2026" {
t.Errorf("Subject = %q", p.Subject)
}
if p.MessageID != "test-001@example.com" {
t.Errorf("MessageID = %q", p.MessageID)
}
if !strings.Contains(p.TextBody, "invoice") {
t.Errorf("TextBody missing 'invoice': %q", p.TextBody)
}
if p.Date.IsZero() {
t.Error("Date is zero")
}
}
func TestParseMultipartWithAttachment(t *testing.T) {
raw := readFixture(t, "multipart.eml")
p, err := mailparser.Parse(raw)
if err != nil {
t.Fatalf("Parse: %v", err)
}
if p.From != "sender@corp.de" {
t.Errorf("From = %q", p.From)
}
if len(p.Attachments) != 1 {
t.Fatalf("expected 1 attachment, got %d", len(p.Attachments))
}
att := p.Attachments[0]
if att.Filename != "angebot.pdf" {
t.Errorf("Attachment filename = %q, want angebot.pdf", att.Filename)
}
if !strings.Contains(att.ContentType, "pdf") {
t.Errorf("ContentType = %q, want pdf", att.ContentType)
}
if att.Size == 0 {
t.Error("attachment size is 0")
}
}
func TestParseRawInline(t *testing.T) {
raw := []byte("From: test@example.com\r\nTo: dest@example.com\r\nSubject: Hello\r\n\r\nBody text here")
p, err := mailparser.Parse(raw)
if err != nil {
t.Fatalf("Parse: %v", err)
}
if p.From != "test@example.com" {
t.Errorf("From = %q", p.From)
}
if len(p.Attachments) != 0 {
t.Errorf("expected 0 attachments, got %d", len(p.Attachments))
}
}
func TestParseMissingDate(t *testing.T) {
raw := []byte("From: test@example.com\r\nSubject: No Date\r\n\r\nNo date header")
p, err := mailparser.Parse(raw)
if err != nil {
t.Fatalf("Parse: %v", err)
}
// Der Parser erfindet bewusst kein Datum: fehlt/unparsbar ist der
// Date-Header, bleibt pm.Date der Zero-Value (parser.go:188-191).
// Den Fallback auf "jetzt" setzt erst die Storage-Schicht beim
// Schreiben von received_at (storage.go:998-1000, 1034-1036).
// So bleibt im Parser unterscheidbar, ob ein Datum aus der Mail
// stammt oder vom Archiv gesetzt wurde (GoBD-Nachvollziehbarkeit).
if !p.Date.IsZero() {
t.Errorf("Date should stay zero when Date header is missing, got %v", p.Date)
}
}