mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-10-16 09:13:17 +01:00
feat(libreoffice): add generateTaggedPdf form field
Tags the PDF without declaring PDF/UA conformance. Today tagging is only available through pdfua, which also writes pdfuaid:part=1 into the XMP metadata. Mirrors the Chromium routes, where generateTaggedPdf and pdfua are separate fields. Defaults to false, so existing requests are unchanged. Closes #1676
This commit is contained in:
committed by
Julien Neuhart
parent
db150b7733
commit
e4ee0f29d6
@@ -1795,6 +1795,7 @@ func InitializeScenario(ctx *godog.ScenarioContext) {
|
||||
ctx.Then(`^the (response|webhook request) PDF\(s\) should declare Factur-X XMP with conformance level "([^"]*)"$`, s.thePdfsShouldDeclareFacturXConformanceLevel)
|
||||
ctx.Then(`^the "([^"]*)" PDF should have (\d+) page\(s\)$`, s.thePdfShouldHavePages)
|
||||
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) be set to landscape orientation$`, s.thePdfShouldBeSetToLandscapeOrientation)
|
||||
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) be tagged$`, s.thePdfShouldBeTagged)
|
||||
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) have a document outline$`, s.thePdfShouldHaveADocumentOutline)
|
||||
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) have the following content at page (\d+):$`, s.thePdfShouldHaveTheFollowingContentAtPage)
|
||||
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) have content matching "([^"]*)" at page (\d+)$`, s.thePdfShouldHaveContentMatchingAtPage)
|
||||
|
||||
44
test/integration/scenario/tagged.go
Normal file
44
test/integration/scenario/tagged.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package scenario
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (s *scenario) thePdfShouldBeTagged(ctx context.Context, name, kind string) error {
|
||||
path := filepath.Join(s.workdir, s.resp.Header().Get("Gotenberg-Trace"), name)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return fmt.Errorf("stat PDF %q: %w", path, err)
|
||||
}
|
||||
|
||||
cmd := []string{"pdfinfo", filepath.Base(path)}
|
||||
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("exec %q: %w", cmd, err)
|
||||
}
|
||||
|
||||
return checkTagged(output, kind != "should NOT")
|
||||
}
|
||||
|
||||
// checkTagged reads the "Tagged" line of pdfinfo, which reflects the Marked
|
||||
// entry of the document catalog's MarkInfo dictionary.
|
||||
func checkTagged(output string, want bool) error {
|
||||
for line := range strings.SplitSeq(output, "\n") {
|
||||
value, found := strings.CutPrefix(strings.TrimSpace(line), "Tagged:")
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
tagged := strings.TrimSpace(value) == "yes"
|
||||
if tagged != want {
|
||||
return fmt.Errorf("expected tagged PDF to be %t, but actual is %t", want, tagged)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid pdfinfo output, no Tagged line: %q", output)
|
||||
}
|
||||
67
test/integration/scenario/tagged_test.go
Normal file
67
test/integration/scenario/tagged_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package scenario
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCheckTagged(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pdfinfo := func(tagged string) string {
|
||||
return "Producer: LibreOffice 26.8\nTagged: " + tagged + "\nPages: 1\n"
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
output string
|
||||
want bool
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "tagged PDF expected and found",
|
||||
output: pdfinfo("yes"),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "untagged PDF expected and found",
|
||||
output: pdfinfo("no"),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "tagged PDF expected but untagged",
|
||||
output: pdfinfo("no"),
|
||||
want: true,
|
||||
wantErr: "expected tagged PDF to be true, but actual is false",
|
||||
},
|
||||
{
|
||||
name: "untagged PDF expected but tagged",
|
||||
output: pdfinfo("yes"),
|
||||
want: false,
|
||||
wantErr: "expected tagged PDF to be false, but actual is true",
|
||||
},
|
||||
{
|
||||
name: "no Tagged line",
|
||||
output: "Pages: 1\n",
|
||||
want: true,
|
||||
wantErr: "invalid pdfinfo output, no Tagged line:",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := checkTagged(tc.output, tc.want)
|
||||
if tc.wantErr == "" {
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err == nil || !strings.Contains(err.Error(), tc.wantErr) {
|
||||
t.Fatalf("expected error containing %q, got: %v", tc.wantErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user