Part of #26. Phase 2 asserted that Get-ArchiveExcludes returns the right list;
this asserts the archive that actually ships. A name can be on the exclude list
and still land in the zip - only opening the zip proves otherwise. Each test
builds a real temp source tree, archives it, and reads back the entries.
66 tests across: TopLevelExclude (files, directories, multiple names, absent
names), recursive junk-directory pruning at top level and any depth, junk
extensions, nested archives, OS junk filenames, script-file inclusion via
-IncludeScriptFiles, ExtraFiles (how zbackup bundles a pg_dump), zip mechanics
(overwrite, destination creation, forward-slash entry paths), and two
end-to-end shapes - a python deploy zip built from the real exclude list, and a
backup of the same tree that must retain .env and uploads.
Two behaviours are pinned deliberately:
- TopLevelExclude matches TOP-LEVEL names only, so a nested backend/.env is
NOT excluded by listing '.env'. That is current behaviour and the reason
deploys rely on server-side preservation; the test exists so changing it is
a decision rather than an accident.
- An all-junk tree throws instead of producing an empty zip - a silent empty
deploy would unpack to nothing on the server.
Verified by mutation testing, which paid for itself immediately: the first run
showed the junk-directory tests were vacuous. Inside a Where-Object, $_ rebinds
to the pipeline item and shadowed Pester's -ForEach value, so the pattern
matched nothing and the tests passed while asserting nothing. Fixed by
capturing the value first; re-run now catches all 8 mutations (disabling
TopLevelExclude, top-level and nested junk pruning, each file filter, and the
empty-archive throw). ZHelpers.ps1 restored byte-for-byte afterwards.