Commit b255639dd5
Verified · cmc
Layout: unified · split
Tests/KeycaskCLITests/ClipboardTests.swift +101
| @@ -64,4 +64,105 @@ import Testing | ||
| 64 | 64 | let r = try cli.run(["clip", "nope"]) |
| 65 | 65 | #expect(r.status == 3) |
| 66 | 66 | } |
| 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 | |
| 67 | 168 | } |