From 8090d9421d08fa2f9cb738e72422f12f7cb48db2 Mon Sep 17 00:00:00 2001 From: Taksh Date: Fri, 31 Jul 2026 11:43:57 +0300 Subject: [PATCH] test: cover ComposerDraftStore isolation, truncation, and reset Pinned cases for mesh/geo/DM keys and the panic-wipe clear path. --- .../Services/ComposerDraftStoreTests.swift | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 bitchatTests/Services/ComposerDraftStoreTests.swift diff --git a/bitchatTests/Services/ComposerDraftStoreTests.swift b/bitchatTests/Services/ComposerDraftStoreTests.swift new file mode 100644 index 00000000..e318a7e0 --- /dev/null +++ b/bitchatTests/Services/ComposerDraftStoreTests.swift @@ -0,0 +1,64 @@ +import Foundation +import Testing +@testable import bitchat +import BitFoundation + +struct ComposerDraftStoreTests { + private func makeDefaults() -> UserDefaults { + let suite = "bitchat.tests.drafts.\(UUID().uuidString)" + return UserDefaults(suiteName: suite)! + } + + @Test func emptyDraftIsNotStored() { + let defaults = makeDefaults() + ComposerDraftStore.save("hello", for: .mesh, in: defaults) + ComposerDraftStore.save(" ", for: .mesh, in: defaults) + // Whitespace-only is still a draft the user typed; empty string clears. + ComposerDraftStore.save("", for: .mesh, in: defaults) + #expect(ComposerDraftStore.load(.mesh, in: defaults).isEmpty) + #expect(defaults.object(forKey: ComposerDraftStore.storageKey) == nil) + } + + @Test func draftsAreIsolatedPerConversation() { + let defaults = makeDefaults() + let peer = PeerID(str: "aabbccddeeff0011") + ComposerDraftStore.save("mesh draft", for: .mesh, in: defaults) + ComposerDraftStore.save("geo draft", for: .location(geohash: "u4pruy"), in: defaults) + ComposerDraftStore.save("dm draft", for: .privatePeer(peer), in: defaults) + + #expect(ComposerDraftStore.load(.mesh, in: defaults) == "mesh draft") + #expect(ComposerDraftStore.load(.location(geohash: "u4pruy"), in: defaults) == "geo draft") + #expect(ComposerDraftStore.load(.privatePeer(peer), in: defaults) == "dm draft") + #expect(ComposerDraftStore.load(.location(geohash: "other"), in: defaults).isEmpty) + } + + @Test func geohashKeysAreCaseInsensitive() { + let defaults = makeDefaults() + ComposerDraftStore.save("city chat", for: .location(geohash: "U4PRUY"), in: defaults) + #expect(ComposerDraftStore.load(.location(geohash: "u4pruy"), in: defaults) == "city chat") + } + + @Test func keyFromPeerAndChannelPrefersPrivate() { + let peer = PeerID(str: "aabbccddeeff0011") + let key = ComposerDraftStore.Key.from( + peerID: peer, + channel: .location(GeohashChannel(level: .city, geohash: "u4pruy")) + ) + #expect(key == .privatePeer(peer)) + } + + @Test func longDraftsAreTruncated() { + let defaults = makeDefaults() + let long = String(repeating: "a", count: ComposerDraftStore.maxDraftLength + 50) + ComposerDraftStore.save(long, for: .mesh, in: defaults) + #expect(ComposerDraftStore.load(.mesh, in: defaults).count == ComposerDraftStore.maxDraftLength) + } + + @Test func resetClearsAllDrafts() { + let defaults = makeDefaults() + ComposerDraftStore.save("keep quiet", for: .mesh, in: defaults) + ComposerDraftStore.reset(in: defaults) + #expect(ComposerDraftStore.load(.mesh, in: defaults).isEmpty) + #expect(defaults.object(forKey: ComposerDraftStore.storageKey) == nil) + } +}