CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
112 lines
3.1 KiB
Go
112 lines
3.1 KiB
Go
package batchsplit
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/pdfcpu/pdfcpu/pkg/api"
|
|
|
|
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testcorpus"
|
|
)
|
|
|
|
const sep = DefaultMarker
|
|
|
|
func pageCount(t *testing.T, b []byte) int {
|
|
t.Helper()
|
|
p := filepath.Join(t.TempDir(), "x.pdf")
|
|
if err := os.WriteFile(p, b, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
n, err := api.PageCountFile(p)
|
|
if err != nil {
|
|
t.Fatalf("ausgabe ist kein gueltiges pdf: %v", err)
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Referenzstapel: erwartete Aufteilung je Stapel (Seitenzahlen der Einzeldokumente).
|
|
func TestSplit_ReferenceBatches(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
pages []string
|
|
want []int
|
|
}{
|
|
{"zwei dokumente", []string{"A1", "A2", sep, "B1"}, []int{2, 1}},
|
|
{"drei dokumente", []string{"A1", sep, "B1", "B2", "B3", sep, "C1"}, []int{1, 3, 1}},
|
|
{"trennseite am anfang und ende", []string{sep, "A1", "A2", sep}, []int{2}},
|
|
{"aufeinanderfolgende trennseiten", []string{"A1", sep, sep, "B1"}, []int{1, 1}},
|
|
{"eine seite", []string{"A1"}, []int{1}},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
parts, err := Split(testcorpus.GenerateStack(c.pages), MarkerDetector{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(parts) != len(c.want) {
|
|
t.Fatalf("teildokumente = %d, want %d", len(parts), len(c.want))
|
|
}
|
|
for i, p := range parts {
|
|
if got := pageCount(t, p); got != c.want[i] {
|
|
t.Errorf("dokument %d: %d seiten, want %d", i, got, c.want[i])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSplit_WithoutSeparatorReturnsInputUnchanged(t *testing.T) {
|
|
in := testcorpus.GenerateStack([]string{"A1", "A2", "A3"})
|
|
parts, err := Split(in, MarkerDetector{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(parts) != 1 || !bytes.Equal(parts[0], in) {
|
|
t.Fatal("stapel ohne trennseite muss unveraendert als ein dokument zurueckkommen")
|
|
}
|
|
}
|
|
|
|
func TestSplit_OnlySeparatorsIsRejected(t *testing.T) {
|
|
_, err := Split(testcorpus.GenerateStack([]string{sep, sep}), MarkerDetector{})
|
|
if !errors.Is(err, ErrOnlySeparators) {
|
|
t.Fatalf("err = %v, want ErrOnlySeparators", err)
|
|
}
|
|
}
|
|
|
|
func TestSplit_InvalidPDFFails(t *testing.T) {
|
|
if _, err := Split([]byte("kein pdf"), MarkerDetector{}); err == nil {
|
|
t.Fatal("ungueltiger inhalt muss einen fehler liefern")
|
|
}
|
|
}
|
|
|
|
func TestSplit_PageContentSurvivesSplit(t *testing.T) {
|
|
parts, err := Split(testcorpus.GenerateStack([]string{"Rechnung-77", sep, "Vertrag-88"}), MarkerDetector{})
|
|
if err != nil || len(parts) != 2 {
|
|
t.Fatalf("parts=%d err=%v", len(parts), err)
|
|
}
|
|
if !contentHas(t, parts[0], "Rechnung-77") || !contentHas(t, parts[1], "Vertrag-88") {
|
|
t.Fatal("seiteninhalt wurde dem falschen teildokument zugeordnet")
|
|
}
|
|
}
|
|
|
|
func contentHas(t *testing.T, pdf []byte, text string) bool {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
in := filepath.Join(dir, "in.pdf")
|
|
_ = os.WriteFile(in, pdf, 0o600)
|
|
if err := api.ExtractContentFile(in, dir, nil, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
files, _ := filepath.Glob(filepath.Join(dir, "*_Content_page_*.txt"))
|
|
for _, f := range files {
|
|
b, _ := os.ReadFile(f)
|
|
if bytes.Contains(b, []byte("("+text+")")) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|