krz/keycask

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

Tests/KeycaskCoreTests/VaultTests.swift

88 lines · 3240 bytes

 1import Foundation
 2import Testing
 3
 4@testable import KeycaskCore
 5
 6@Suite struct VaultTests {
 7    func idA() -> EntryID { EntryID("aaaa2222")! }
 8    func idB() -> EntryID { EntryID("bbbb3333")! }
 9
10    @Test func addRejectsDuplicateID() throws {
11        var v = Vault()
12        try v.add(Entry(id: idA(), name: "gh", password: "p"))
13        #expect(throws: KeycaskError.duplicateID(idA())) {
14            try v.add(Entry(id: idA(), name: "other", password: "p"))
15        }
16        #expect(v.entries.count == 1)
17    }
18
19    @Test func removeUnknownIsNotFound() {
20        var v = Vault()
21        #expect(throws: KeycaskError.notFound("aaaa2222")) { try v.remove(id: idA()) }
22    }
23
24    @Test func updateSetsUpdatedAndNormalizesTags() throws {
25        let t0 = Date(timeIntervalSince1970: 1_000)
26        let t1 = Date(timeIntervalSince1970: 2_000.9)
27        var v = Vault()
28        try v.add(Entry(id: idA(), name: "gh", password: "p", now: t0))
29        try v.update(id: idA(), now: t1) { e in
30            e.tags = ["z", "A", "a"]
31            e.password = "q"
32        }
33        let e = v.entry(id: idA())!
34        #expect(e.password == "q")
35        #expect(e.tags == ["A", "z"])
36        #expect(e.created == t0)
37        #expect(e.updated == Date(timeIntervalSince1970: 2_000))
38    }
39
40    @Test func resolvePrefersIDThenUniqueName() throws {
41        var v = Vault()
42        try v.add(Entry(id: idA(), name: "gh", password: "p"))
43        try v.add(Entry(id: idB(), name: "aaaa2222", password: "p"))
44        #expect(try v.resolve("aaaa2222").id == idA())
45        #expect(try v.resolve("gh").id == idA())
46        #expect(try v.resolve("bbbb3333").id == idB())
47    }
48
49    @Test func resolveReportsAmbiguousWithAllCandidates() throws {
50        var v = Vault()
51        let a = Entry(id: idA(), name: "gh", password: "p")
52        let b = Entry(id: idB(), name: "gh", password: "p")
53        try v.add(a)
54        try v.add(b)
55        #expect(throws: KeycaskError.ambiguous(name: "gh", candidates: [a, b])) {
56            try v.resolve("gh")
57        }
58    }
59
60    @Test func resolveUnknownIsNotFound() {
61        #expect(throws: KeycaskError.notFound("nope")) { try Vault().resolve("nope") }
62    }
63
64    @Test func filterAndSearch() throws {
65        var v = Vault()
66        try v.add(Entry(id: idA(), name: "GitHub", password: "p", tags: ["dev"]))
67        try v.add(Entry(id: idB(), name: "bank", password: "p", url: "https://bank.example"))
68        #expect(v.filter(tag: "DEV").map(\.id) == [idA()])
69        #expect(v.search("example").map(\.id) == [idB()])
70        #expect(v.search("zzz").isEmpty)
71    }
72
73    @Test func sortedEntriesOrderByNameThenID() throws {
74        var v = Vault()
75        try v.add(Entry(id: idB(), name: "gh", password: "p"))
76        try v.add(Entry(id: idA(), name: "gh", password: "p"))
77        try v.add(Entry(id: EntryID("cccc4444")!, name: "Alpha", password: "p"))
78        #expect(v.sortedEntries.map(\.id.rawValue) == ["cccc4444", "aaaa2222", "bbbb3333"])
79    }
80
81    @Test func addNormalizesTagsSetAfterInit() throws {
82        var e = Entry(id: idA(), name: "gh", password: "p")
83        e.tags = ["z", "A", "a", " b "]
84        var v = Vault()
85        try v.add(e)
86        #expect(v.entry(id: idA())!.tags == ["A", "b", "z"])
87    }
88}