eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1import XCTest
2@testable import LChatCore
3
4// 🤖 The shared avatar-thumbnail cache the notification extension reads to put
5// a sender's face on a banner. Network-free: sync's fetch path is exercised
6// only for entries whose source marker is stale, so the tests drive the
7// skip/remove/roundtrip contract with seeded files and unreachable URLs.
8final class SharedAvatarCacheTests: XCTestCase {
9 private var dir: URL!
10
11 override func setUp() {
12 super.setUp()
13 dir = FileManager.default.temporaryDirectory
14 .appendingPathComponent("avatar-cache-tests-\(UUID().uuidString)", isDirectory: true)
15 SharedAvatarCache.directoryOverride = dir
16 }
17
18 override func tearDown() {
19 SharedAvatarCache.directoryOverride = nil
20 try? FileManager.default.removeItem(at: dir)
21 super.tearDown()
22 }
23
24 private func source(blobID: String) -> AvatarSource {
25 // .1 is reserved/unroutable → any fetch attempt fails fast.
26 AvatarSource(blobID: blobID, keyB64: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
27 baseURL: URL(string: "http://192.0.2.1")!, token: "t")
28 }
29
30 func testStoreThenReadRoundtrip() {
31 let jpeg = Data([0xff, 0xd8, 0xff, 0xe0, 1, 2, 3])
32 SharedAvatarCache.store(jpeg: jpeg, blobID: "b1", origin: "https://a.example", uid: "u1")
33 XCTAssertEqual(SharedAvatarCache.imageData(origin: "https://a.example", uid: "u1"), jpeg)
34 // Same uid on another instance is a different person — different slot.
35 XCTAssertNil(SharedAvatarCache.imageData(origin: "https://b.example", uid: "u1"))
36 }
37
38 func testStemIsFilesystemSafeAndDistinct() {
39 let a = SharedAvatarCache.fileStem(origin: "https://a.example", uid: "u/1")
40 let b = SharedAvatarCache.fileStem(origin: "https://b.example", uid: "u/1")
41 XCTAssertNotEqual(a, b)
42 XCTAssertTrue(a.allSatisfy(\.isHexDigit))
43 XCTAssertEqual(a, SharedAvatarCache.fileStem(origin: "https://a.example", uid: "u/1"))
44 }
45
46 func testSyncKeepsUnchangedEntryWithoutFetching() async {
47 let jpeg = Data([9, 9, 9])
48 SharedAvatarCache.store(jpeg: jpeg, blobID: "b1", origin: "o", uid: "u1")
49 // Marker matches the stored blob → sync must not touch the file (a
50 // fetch would fail against the unroutable host and drop it).
51 await SharedAvatarCache.sync(origin: "o", avatars: [("u1", source(blobID: "b1"))])
52 XCTAssertEqual(SharedAvatarCache.imageData(origin: "o", uid: "u1"), jpeg)
53 }
54
55 func testSyncKeepsStaleThumbnailWhenFetchFails() async {
56 let jpeg = Data([9, 9, 9])
57 SharedAvatarCache.store(jpeg: jpeg, blobID: "old", origin: "o", uid: "u1")
58 // Photo changed but the refetch fails → the old face beats no face.
59 await SharedAvatarCache.sync(origin: "o", avatars: [("u1", source(blobID: "new"))])
60 XCTAssertEqual(SharedAvatarCache.imageData(origin: "o", uid: "u1"), jpeg)
61 }
62
63 func testSyncRemovesEntryWhenPhotoCleared() async {
64 SharedAvatarCache.store(jpeg: Data([1]), blobID: "b1", origin: "o", uid: "u1")
65 await SharedAvatarCache.sync(origin: "o", avatars: [("u1", nil)])
66 XCTAssertNil(SharedAvatarCache.imageData(origin: "o", uid: "u1"))
67 }
68}
69