mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
# Description of Changes Change tool APIs to use structured definitions for input/output/type info because we need that info to be able to validate whether policies can actually successfully work based on whether one tool accepts the output of another. There were various bugs in the previous string definitions because of either misspellings or just incorrect definitions, so I've gone through and fixed all that I can find. <img width="729" height="271" alt="image" src="https://github.com/user-attachments/assets/08357e96-6fbb-4b9c-ba4d-8995420c7b86" /> <img width="749" height="264" alt="image" src="https://github.com/user-attachments/assets/76f46284-1866-4b64-b1ed-2480e01866e9" /> <img width="402" height="636" alt="image" src="https://github.com/user-attachments/assets/8f7a36ca-2845-4f14-a2df-ec9c772e66f6" /> <img width="393" height="317" alt="image" src="https://github.com/user-attachments/assets/46d8b891-9820-4ce3-8109-a8b782277037" /> --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
280 lines
11 KiB
JSON
280 lines
11 KiB
JSON
{
|
|
"$comment": [
|
|
"Shared conformance cases for the tool I/O compatibility check.",
|
|
"Run by Java (ToolChainValidatorConformanceTest), the frontend (toolIOCompat.test.ts) and the",
|
|
"engine (test_tool_io_compat.py) against their own implementations, which must agree.",
|
|
"Specs are synthetic, so retyping a real endpoint never invalidates a case.",
|
|
"'expected' is matched on stepIndex/severity/code; messages are free text."
|
|
],
|
|
"specs": {
|
|
"pdfToPdf": { "accepts": ["PDF"], "produces": "PDF", "arity": "SISO", "cases": [] },
|
|
"pdfToPdfSplit": { "accepts": ["PDF"], "produces": "PDF", "arity": "SIMO", "cases": [] },
|
|
"pdfMerge": { "accepts": ["PDF"], "produces": "PDF", "arity": "MISO", "cases": [] },
|
|
"addPassword": { "accepts": ["PDF"], "produces": "PDF_ENCRYPTED", "arity": "SISO", "cases": [] },
|
|
"removePassword": { "accepts": ["PDF_ENCRYPTED"], "produces": "PDF", "arity": "SISO", "cases": [] },
|
|
"extractImages": { "accepts": ["PDF"], "produces": "IMAGE", "arity": "SIMO", "cases": [] },
|
|
"imageToPdf": { "accepts": ["IMAGE"], "produces": "PDF", "arity": "MISO", "cases": [] },
|
|
"getAttachments": { "accepts": ["PDF"], "produces": "ZIP", "arity": "SISO", "cases": [] },
|
|
"getInfo": { "accepts": ["PDF"], "produces": "JSON", "arity": "SISO", "cases": [] },
|
|
"validateOnly": { "accepts": ["PDF"], "produces": "NONE", "arity": "SISO", "cases": [] },
|
|
"anyToPdf": { "accepts": ["ANY"], "produces": "PDF", "arity": "SISO", "cases": [] },
|
|
"pdfToAny": { "accepts": ["PDF"], "produces": "ANY", "arity": "SISO", "cases": [] },
|
|
"pdfOrImage": { "accepts": ["PDF", "IMAGE"], "produces": "PDF", "arity": "SISO", "cases": [] },
|
|
"pdfToImageConfigurable": {
|
|
"accepts": ["PDF"],
|
|
"produces": "IMAGE",
|
|
"arity": "SIMO",
|
|
"cases": [
|
|
{
|
|
"when": [{ "param": "singleOrMultiple", "matches": ["single"] }],
|
|
"produces": "IMAGE",
|
|
"arity": "SISO"
|
|
}
|
|
]
|
|
},
|
|
"addPasswordConfigurable": {
|
|
"accepts": ["PDF"],
|
|
"produces": "PDF_ENCRYPTED",
|
|
"arity": "SISO",
|
|
"cases": [
|
|
{
|
|
"when": [{ "param": "password", "matches": [""] }],
|
|
"produces": "PDF",
|
|
"arity": "SISO"
|
|
}
|
|
]
|
|
},
|
|
"pdfToImageMixedCase": {
|
|
"accepts": ["PDF"],
|
|
"produces": "IMAGE",
|
|
"arity": "SIMO",
|
|
"cases": [
|
|
{
|
|
"when": [{ "param": "singleOrMultiple", "matches": [" SiNgLe "] }],
|
|
"produces": "IMAGE",
|
|
"arity": "SISO"
|
|
}
|
|
]
|
|
},
|
|
"addPasswordTwoKeys": {
|
|
"accepts": ["PDF"],
|
|
"produces": "PDF_ENCRYPTED",
|
|
"arity": "SISO",
|
|
"cases": [
|
|
{
|
|
"when": [
|
|
{ "param": "password", "matches": [""] },
|
|
{ "param": "ownerPassword", "matches": [""] }
|
|
],
|
|
"produces": "PDF",
|
|
"arity": "SISO"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"cases": [
|
|
{
|
|
"name": "a plain pdf chain is clean",
|
|
"steps": [{ "spec": "pdfToPdf" }, { "spec": "pdfToPdf" }],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "an empty chain is clean",
|
|
"steps": [],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "a single step is never a transition",
|
|
"steps": [{ "spec": "extractImages" }],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "encrypting then editing is rejected",
|
|
"steps": [{ "spec": "addPassword" }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" }]
|
|
},
|
|
{
|
|
"name": "encrypting then decrypting is allowed",
|
|
"steps": [{ "spec": "addPassword" }, { "spec": "removePassword" }],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "decrypting then editing is allowed",
|
|
"steps": [{ "spec": "removePassword" }, { "spec": "pdfToPdf" }],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "an ordinary tool cannot be handed an encrypted pdf from source",
|
|
"sourceFormat": "PDF_ENCRYPTED",
|
|
"steps": [{ "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 0, "severity": "ERROR", "code": "source-mismatch" }]
|
|
},
|
|
{
|
|
"name": "remove-password is the one thing an encrypted source can start with",
|
|
"sourceFormat": "PDF_ENCRYPTED",
|
|
"steps": [{ "spec": "removePassword" }, { "spec": "pdfToPdf" }],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "extracted images cannot feed a pdf tool",
|
|
"steps": [{ "spec": "extractImages" }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" }]
|
|
},
|
|
{
|
|
"name": "extracted images can feed an image tool, and fan in",
|
|
"steps": [{ "spec": "extractImages" }, { "spec": "imageToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "INFO", "code": "fan-in" }]
|
|
},
|
|
{
|
|
"name": "splitting then a single-file tool fans out",
|
|
"steps": [{ "spec": "pdfToPdfSplit" }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "INFO", "code": "fan-out" }]
|
|
},
|
|
{
|
|
"name": "splitting then merging fans in",
|
|
"steps": [{ "spec": "pdfToPdfSplit" }, { "spec": "pdfMerge" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "INFO", "code": "fan-in" }]
|
|
},
|
|
{
|
|
"name": "an archive deliverable does not feed a pdf tool",
|
|
"steps": [{ "spec": "getAttachments" }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" }]
|
|
},
|
|
{
|
|
"name": "a json report does not feed a pdf tool",
|
|
"steps": [{ "spec": "getInfo" }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" }]
|
|
},
|
|
{
|
|
"name": "a step producing no file terminates the chain",
|
|
"steps": [{ "spec": "validateOnly" }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" }]
|
|
},
|
|
{
|
|
"name": "a tool accepting anything swallows any upstream output",
|
|
"steps": [{ "spec": "extractImages" }, { "spec": "anyToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "INFO", "code": "fan-out" }]
|
|
},
|
|
{
|
|
"name": "a tool producing anything satisfies any downstream input",
|
|
"steps": [{ "spec": "pdfToAny" }, { "spec": "imageToPdf" }],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "a source of unknown type is not checked against step one",
|
|
"steps": [{ "spec": "imageToPdf" }],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "a multi-format tool accepts either branch",
|
|
"steps": [{ "spec": "extractImages" }, { "spec": "pdfOrImage" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "INFO", "code": "fan-out" }]
|
|
},
|
|
{
|
|
"name": "an unconfigured parameter-dependent output only warns",
|
|
"steps": [{ "spec": "addPasswordConfigurable" }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "WARN", "code": "output-uncertain" }]
|
|
},
|
|
{
|
|
"name": "configuring the parameter to the encrypting branch makes it an error",
|
|
"steps": [
|
|
{ "spec": "addPasswordConfigurable", "parameters": { "password": "hunter2" } },
|
|
{ "spec": "pdfToPdf" }
|
|
],
|
|
"expected": [{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" }]
|
|
},
|
|
{
|
|
"name": "configuring the parameter to the non-encrypting branch clears it",
|
|
"steps": [
|
|
{ "spec": "addPasswordConfigurable", "parameters": { "password": "" } },
|
|
{ "spec": "pdfToPdf" }
|
|
],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "a multi-condition case needs every condition to hold",
|
|
"steps": [
|
|
{
|
|
"spec": "addPasswordTwoKeys",
|
|
"parameters": { "password": "", "ownerPassword": "hunter2" }
|
|
},
|
|
{ "spec": "pdfToPdf" }
|
|
],
|
|
"expected": [{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" }]
|
|
},
|
|
{
|
|
"name": "a multi-condition case applies when every condition holds",
|
|
"steps": [
|
|
{ "spec": "addPasswordTwoKeys", "parameters": { "password": "", "ownerPassword": "" } },
|
|
{ "spec": "pdfToPdf" }
|
|
],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "a multi-condition case is unresolved when one condition is unconfigured",
|
|
"steps": [
|
|
{ "spec": "addPasswordTwoKeys", "parameters": { "password": "" } },
|
|
{ "spec": "pdfToPdf" }
|
|
],
|
|
"expected": [{ "stepIndex": 1, "severity": "WARN", "code": "output-uncertain" }]
|
|
},
|
|
{
|
|
"name": "the single branch of an arity case produces one file, so no fan-out",
|
|
"steps": [
|
|
{ "spec": "pdfToImageConfigurable", "parameters": { "singleOrMultiple": "single" } },
|
|
{ "spec": "imageToPdf" }
|
|
],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "the default branch of an arity case fans in",
|
|
"steps": [
|
|
{ "spec": "pdfToImageConfigurable", "parameters": { "singleOrMultiple": "multiple" } },
|
|
{ "spec": "imageToPdf" }
|
|
],
|
|
"expected": [{ "stepIndex": 1, "severity": "INFO", "code": "fan-in" }]
|
|
},
|
|
{
|
|
"name": "a condition matches regardless of the casing and padding it was declared with",
|
|
"steps": [
|
|
{ "spec": "pdfToImageMixedCase", "parameters": { "singleOrMultiple": "SINGLE" } },
|
|
{ "spec": "imageToPdf" }
|
|
],
|
|
"expected": []
|
|
},
|
|
{
|
|
"name": "a condition declared in mixed case still fails on a genuinely different value",
|
|
"steps": [
|
|
{ "spec": "pdfToImageMixedCase", "parameters": { "singleOrMultiple": "multiple" } },
|
|
{ "spec": "imageToPdf" }
|
|
],
|
|
"expected": [{ "stepIndex": 1, "severity": "INFO", "code": "fan-in" }]
|
|
},
|
|
{
|
|
"name": "an undeclared step warns and stops the chain being checked past it",
|
|
"steps": [{ "spec": "addPassword" }, { "spec": null }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "WARN", "code": "undeclared-operation" }]
|
|
},
|
|
{
|
|
"name": "the source format is not re-applied to a step that follows an undeclared one",
|
|
"sourceFormat": "PDF_ENCRYPTED",
|
|
"steps": [{ "spec": "removePassword" }, { "spec": null }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 1, "severity": "WARN", "code": "undeclared-operation" }]
|
|
},
|
|
{
|
|
"name": "an undeclared first step does not pass the source format on to the next step",
|
|
"sourceFormat": "PDF_ENCRYPTED",
|
|
"steps": [{ "spec": null }, { "spec": "pdfToPdf" }],
|
|
"expected": [{ "stepIndex": 0, "severity": "WARN", "code": "undeclared-operation" }]
|
|
},
|
|
{
|
|
"name": "every broken transition is reported, not just the first",
|
|
"steps": [{ "spec": "extractImages" }, { "spec": "pdfToPdf" }, { "spec": "imageToPdf" }],
|
|
"expected": [
|
|
{ "stepIndex": 1, "severity": "ERROR", "code": "format-mismatch" },
|
|
{ "stepIndex": 2, "severity": "ERROR", "code": "format-mismatch" }
|
|
]
|
|
}
|
|
]
|
|
}
|