Revision checks compared objects only. A later revision that pointed the
trailer at another catalog already present in the signed file changed no
object, so the signature stayed valid while the reader showed a different
document. A /Root that differs from the signed revision's is now a
disallowed change to the document structure.
An OCSP response's signer counted as the issuer itself whenever its
certificate carried the issuer's subject name. A response naming its
responder by key hash could embed a certificate for any key with the
issuer's name copied in, skip the delegation checks, and mark a valid
certificate revoked. Whether the responder is the issuer now follows from
how it was selected (the issuer's own name or key hash); every embedded
certificate must be signed by the issuer and carry the OCSP-signing
purpose.
The example passed a constant seed to set_encryption. AES-256 derives the
file key from the seed alone, so anyone could rebuild the key and read a
file it protected without either password. The seed now comes from the
operating system's randomness through RandomState, as in the engine.
The qpdf oracle test wrote into temp_dir()/pdfcraft-enc-<pid>, reusing the
directory if it existed and following any symlink inside it, so another
local account could prepare it and have the test overwrite a file of the
developer's. The directory now has an unpredictable name, is created by
the test (mode 0700 on Unix) and the files are created new.
A stream that named its own crypt filter (/Filter /Crypt with
/DecodeParms /Name) kept that name when the document was given new
password protection. The new /Encrypt defines only /StdCF, so the
inherited name resolved to /Identity and the stream was written in
clear into a file the user asked to protect. When saving with protection
applied by set_encryption, a selector the new handler does not define is
removed with its parameters and the stream follows the new policy.
Saving with the original handler keeps the source's selectors.
Saving with encryption left a dictionary's /Contents in clear whenever it
had a string /Contents and an array /ByteRange, whatever else it was. A
source file could add a /ByteRange to an ordinary annotation and its
comment text was then written unencrypted. A dictionary with a /Subtype or
a /Type other than Sig or DocTimeStamp is never a signature dictionary, so
its /Contents is encrypted like any other string.
* Build each crate's integration tests as one binary
Every tests/*.rs file is its own executable that links the whole crate
graph. Move each crate's test files into tests/it/ as modules of one
tests/it/main.rs, for apps/pdfcraft, apps/pdfcraft-cli, automation, cos,
crypt, engine, render, sign and ui-egui. ui-egui's ui_group binary and
the support modules move into tests/it/ too. Crates with a single test
file keep it. The test executables go from 150 to 52, and every crate
runs the same number of tests as before.
ui-egui perf keeps its own binary (own process): its frame-time budgets
would charge each measurement for the other tests running beside it.
What the move needs:
- include_str!/include_bytes! and #[path] paths gain one "../".
- ui-egui: one GPU lock in tests/it/main.rs replaces the five per-file
ones (content, document_links, editing, fill_sign, view), so one
process creates one wgpu device at a time. The drop-line test in ui.rs
and the screenshot blocks behind PDFCRAFT_*_SHOT(S) and
CRAFT_UI_DOCKING_DIR, which render without holding it, take it too.
- pdfcraft winit_wayland_scroll: the vendored winit source it compiles
names crate::event, so that shim lives in main.rs.
- parity evidence names the new paths.
* Name the one-binary test paths in docs and comments
- READMEs, docs, ATTRIBUTION and source comments name tests/it/<file>.rs.
- The oracle README's example filters with --test it encryption::qpdf_agrees.
- pdfcraft's GPU lock comment points at the UI tests' shared lock in
crates/ui-egui/tests/it/main.rs.
Each font-family in assets/demo/showcase.html named only a specific font with
no generic fallback. Add an appropriate generic (serif/sans-serif/monospace/
cursive/math) so text still renders if the specific face is unavailable.
Windows CI has a default printer, so the button still read Print in the
frame where the test cleared the printer; the other print tests already
run a frame first.
Each kittest harness creates its own wgpu/Vulkan instance on first render, and
lavapipe segfaults when one test creates an instance while another renders
(core dump: vkCreateSampler in libvulkan during a concurrent vkCreateInstance).
The batch tripled the rendering tests in editing.rs. editing and content take
the GPU lock view.rs and fill_sign.rs already use. Crashes over default-thread
runs: editing 11/40 before, 0/40 after; content 4/20 before, 0/20 after.
Albanian, Catalan, Finnish, Hindi, Korean, Indonesian and Romanian get all
22 text-field-table strings; Brazilian Portuguese gets the 4 limit messages
its full-union test requires. AI-assisted, marked in ATTRIBUTION.toml.
a_dead_options_read_wakes_an_idle_dialog asserted the dialog was idle after one
Harness::run. The print preview's page rasters render on the pool and ask for a
frame every 30 ms until they arrive; with kittest's 0.25 s step that is an
immediate repaint, so on a loaded machine run() exceeded its 4 steps
(canvas.rs finish_render_frame). The test now steps until no render is pending.
Under 24 parallel copies the old test failed 3 of 192 runs, the new one 0 of 72.
#3525 asked for its snapshots to be regenerated once the batch is
assembled. Each change comes from a merged PR:
- panel_compare: the Show: Text / Visual filters (#2607).
- panel_layers: the Layer options button (#2731, Reset to Initial Visibility).
- panel_pages: the thumbnail size label, buttons and slider (#3828).
#3781 draws a Fill & Sign line across the page as /Rotate displays it, so on
a page turned a quarter its rect runs along user y. #3520's test expected
the line along user x on every page and failed on the /Rotate 90 cases.
The test's points and rects are now given along the line, so each rotation
checks the same grow, shrink and release.
#2240 (on main before this round) took the Read tab out of the mode bar.
#3010 and #3022 were written against a mode bar that still had it, so
their five tests looked for a Read button that is gone. The tests now
check All tools in its place where the scrolled content reaches under it
(added text, the Fill & Sign type box). Page 1's text and the form's name
field start right of All tools, so those tests check Edit, Convert and
E-Sign, the tabs they lie under.
English fill (the "Untranslated" section of each catalogue), for keys the
coverage tests only need present:
- ca, fi, ro, pt-br: keys other catalogues gained (print, thumbnails,
layers, signature checks, Reshape comment, Remove {standard}
identification)
- sq: UI literals and the visible-signature labels
- hi, ko, id: calculation-order, rich-text and print/thumbnail literals
- pl: signature-check wordings
AI-assisted translation (noted in ATTRIBUTION.toml):
- cs: the four new signature-check wordings and Remove {standard}
identification, since Czech asserts every entry is translated
Lao's file.word_count command id said its own id; it reads as the
plain "Word count…" translation.
#3515 measures a growing non-interactive field at its text's scale but
with a widget's 4pt of padding, while the layout draws its text without
it. Once #3521 fits lines by their ink, the narrower measuring width
wrapped to one more line than the drawn text, leaving a blank line
below it. The measurement leaves out the padding the draw doesn't have.
#2609 put the Japanese faces ahead of the bundled Inter face and rewrote
the #1760 test to expect Inter, which holds only without craft-fonts.
With CRAFT_FONTS_DIR, BIZ UDPGothic has ő and draws it. The test now
expects the Japanese sans face when the build has one, Inter otherwise.
#2425 writes opaque rasters as 8-bit RGB; the owner-password render test
was written against the RGBA encoder. A rendered page is always opaque,
so the test asserts RGB and still counts inked pixels.
Prepare a form's arrow-key nudge (#2621) consumed Alt+↑/↓ as plain arrows,
because egui's consume_key ignores an extra Alt. Calculation order (#3733)
moves the selected field with Alt+↑/↓, so the field moved a point on the
page instead of in the order. The nudge now leaves Alt+arrow alone.
The track merges used a union driver for these files, which kept two
versions of a milestone row or status line wherever two tracks changed the
same one. They are recomputed as base plus each track's changes, with two
edits of one line combined into one line. The status lines that #2805, #3808
and #3532 put above the Stage line join the status list below it, newest
first.
#3101's page_gap_labels_are_translated_in_every_catalog asserts that every
catalog translates its two labels. The Finnish, Albanian, Thai, Catalan,
Romanian, Lao and Central Kurdish catalogs from track t12 lack them. The
translations are AI-assisted and noted as such in ATTRIBUTION.toml.