krz/keycask

Password manager: Swift core library, CLI for macOS/Linux/Windows, iOS/macOS app. cli password-manager swift

Commit b255639dd5

b255639dd5e3fe710dd36d79f58b6fa962e52f11

parent: bd8d5569eb

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-18 01:24 UTC

Add end-to-end clipboard tests

Layout: unified · split

Tests/KeycaskCLITests/ClipboardTests.swift +101
@@ -64,4 +64,105 @@ import Testing
6464 let r = try cli.run(["clip", "nope"])
6565 #expect(r.status == 3)
6666 }
67
68 #if !os(Windows)
69 /// A temp directory of clipboard tools backed by a file, so tests never
70 /// touch the real clipboard.
71 struct Stub {
72 let dir: URL
73
74 var file: URL { dir.appendingPathComponent("clip.txt") }
75 var environment: [String: String] { ["PATH": "\(dir.path):/bin:/usr/bin"] }
76
77 init() throws {
78 dir = FileManager.default.temporaryDirectory
79 .appendingPathComponent("keycask-clip-stub-\(UUID().uuidString)")
80 try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
81 #if os(macOS)
82 try install("pbcopy", "#!/bin/sh\ncat > \"$(dirname \"$0\")/clip.txt\"\n")
83 try install(
84 "pbpaste", "#!/bin/sh\ncat \"$(dirname \"$0\")/clip.txt\" 2>/dev/null\n")
85 #else
86 try install(
87 "xclip",
88 """
89 #!/bin/sh
90 for a in "$@"; do
91 if [ "$a" = "-o" ]; then
92 cat "$(dirname "$0")/clip.txt" 2>/dev/null
93 exit 0
94 fi
95 done
96 cat > "$(dirname "$0")/clip.txt"
97
98 """)
99 #endif
100 }
101
102 func contents() -> String {
103 (try? String(contentsOf: file, encoding: .utf8)) ?? ""
104 }
105
106 func set(_ text: String) throws {
107 try Data(text.utf8).write(to: file)
108 }
109
110 private func install(_ name: String, _ script: String) throws {
111 let url = dir.appendingPathComponent(name)
112 try Data(script.utf8).write(to: url)
113 try FileManager.default.setAttributes(
114 [.posixPermissions: 0o755], ofItemAtPath: url.path)
115 }
116 }
117
118 @Test func clipCopiesTheFieldThroughTheTool() throws {
119 let cli = try CLI.initialized()
120 let stub = try Stub()
121 try cli.run(["add", "t", "--generate"])
122 let expected = try cli.run(["show", "t", "--field", "password"]).stdout
123 .trimmingCharacters(in: .whitespacesAndNewlines)
124
125 let start = Date()
126 let r = try cli.run(["clip", "t"], extraEnvironment: stub.environment)
127 let elapsed = Date().timeIntervalSince(start)
128
129 #expect(r.status == 0)
130 #expect(r.stdout.contains("copied password of t"))
131 #expect(stub.contents() == expected)
132 #expect(elapsed < 5)
133 }
134
135 @Test func generateCopyWritesTheTool() throws {
136 let cli = try CLI()
137 let stub = try Stub()
138 let r = try cli.run(
139 ["generate", "--copy"], passphrase: nil, extraEnvironment: stub.environment)
140 #expect(r.status == 0)
141 let copied = stub.contents()
142 #expect(copied.count == 24)
143 #expect(!r.stdout.contains(copied))
144 }
145
146 @Test func daemonClearsWhenClipboardStillHoldsSecret() throws {
147 let cli = try CLI()
148 let stub = try Stub()
149 try stub.set("probe")
150 let r = try cli.run(
151 ["clipboard-daemon", "1"], stdin: #"{"secret":"probe"}"#, passphrase: nil,
152 extraEnvironment: stub.environment)
153 #expect(r.status == 0)
154 #expect(stub.contents() == "")
155 }
156
157 @Test func daemonLeavesForeignContentAlone() throws {
158 let cli = try CLI()
159 let stub = try Stub()
160 try stub.set("other")
161 let r = try cli.run(
162 ["clipboard-daemon", "1"], stdin: #"{"secret":"probe"}"#, passphrase: nil,
163 extraEnvironment: stub.environment)
164 #expect(r.status == 0)
165 #expect(stub.contents() == "other")
166 }
167 #endif
67168}