import Foundation import Testing @testable import Kanban /// **The sandbox verification the card's design ruling asks for**: "prefer … `Process`+`/usr/bin/ /// ditto` … VERIFY in a sandboxed build". /// /// `KanbanTests` is host-application-hosted (`TEST_HOST` in `project.yml` points at the built /// `Lanework.app`), so this suite runs *inside* the real, sandboxed app process — /// `Kanban.entitlements`'s `com.apple.security.app-sandbox` and all — rather than in a bare XCTest /// bundle with none of the app's confinement. A green run here is empirical: `/usr/bin/ditto`, /// spawned as this app's child, can read a folder this process owns and write a `.zip` beside it, /// under the same entitlements a real File ▸ Share… run would have. That is the closest this suite /// can get to the real button without driving AppKit (`BoardSharePresentation`'s own boundary). @Suite("DittoZipArchiver") struct DittoZipArchiverTests { @Test("A folder zips inside the sandbox, and the result is a real zip") func zipsInsideTheSandbox() throws { let fixture = try WriterFixture() defer { fixture.tearDown() } let source = fixture.url("Payload") try FileManager.default.createDirectory(at: source, withIntermediateDirectories: true) try Data("hello from the sandbox\n".utf8).write(to: source.appendingPathComponent("note.txt")) try FileManager.default.createDirectory( at: source.appendingPathComponent("nested", isDirectory: true), withIntermediateDirectories: true ) try Data([0x01, 0x02, 0x03]).write(to: source.appendingPathComponent("nested/data.bin")) let destination = fixture.url("Payload.zip") try DittoZipArchiver.zip(contentsOf: source, to: destination) #expect(FileManager.default.fileExists(atPath: destination.path)) let bytes = try Data(contentsOf: destination) #expect(!bytes.isEmpty) // The local file header signature `PK\x03\x04` — proof this is an actual zip archive and // not, say, an empty file `ditto` merely touched. #expect(bytes.prefix(4) == Data([0x50, 0x4B, 0x03, 0x04])) } @Test("A source that doesn't exist is a failure, not a silent empty archive") func missingSourceFails() throws { let fixture = try WriterFixture() defer { fixture.tearDown() } let missing = fixture.url("Never") let destination = fixture.url("Never.zip") #expect(throws: DittoZipArchiver.Failure.self) { try DittoZipArchiver.zip(contentsOf: missing, to: destination) } #expect(!FileManager.default.fileExists(atPath: destination.path)) } }