mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 17:05:21 +00:00
Inject notification/favorites singletons through coordinator contexts
NotificationService.shared and FavoritesPersistenceService.shared accesses across nine coordinators/components consolidate into ChatViewModel witnesses behind intent-named context members (notifyPrivateMessage, notifyMention, favoriteRelationship(forNoiseKey:), allFavoriteRelationships, postLocalNotification, ...). Singleton reach from coordinators is now zero; nine new tests cover previously untestable notification/favorites flows. Also root-causes the long-flaky gift-wrap dedup test: parallel tests share LocationChannelManager.shared, so channel-switch tests trigger clearProcessedNostrEvents() on every live ChatViewModel, wiping the dedup record mid-test. The invariant (forged-signature copies never poison dedup) now lives as a deterministic NostrInboundPipeline mock-context test; two Schnorr concurrency probes added along the way stay as regression guards for the P256K shared-context assumptions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,11 +7,11 @@
|
||||
// `ChatViewModel`, following the `ChatDeliveryCoordinatorContextTests` /
|
||||
// `ChatPrivateConversationCoordinatorContextTests` exemplars.
|
||||
//
|
||||
// Scope note: flows that hit process-wide singletons are intentionally not
|
||||
// exercised here — `checkForMentions` / haptics (NotificationService.shared,
|
||||
// UIApplication) and the geohash branch of `sendPublicRaw`
|
||||
// (NostrRelayManager.shared, GeoRelayDirectory.shared). The mesh branch of
|
||||
// `sendPublicRaw` and all timeline/store/blocking flows are covered.
|
||||
// Scope note: haptics (UIApplication) and the geohash branch of
|
||||
// `sendPublicRaw` (NostrRelayManager.shared, GeoRelayDirectory.shared) are
|
||||
// intentionally not exercised here. `checkForMentions` posts through the
|
||||
// injected context (`notifyMention(from:message:)`) and is covered, as are
|
||||
// the mesh branch of `sendPublicRaw` and all timeline/store/blocking flows.
|
||||
//
|
||||
|
||||
import Testing
|
||||
@@ -249,6 +249,13 @@ private final class MockChatPublicConversationContext: ChatPublicConversationCon
|
||||
prewarmedMessageIDs.append(message.id)
|
||||
}
|
||||
|
||||
// Notifications
|
||||
private(set) var mentionNotifications: [(sender: String, message: String)] = []
|
||||
|
||||
func notifyMention(from sender: String, message: String) {
|
||||
mentionNotifications.append((sender, message))
|
||||
}
|
||||
|
||||
static let dummyIdentity = NostrIdentity(
|
||||
privateKey: Data(repeating: 0x11, count: 32),
|
||||
publicKey: Data(repeating: 0x22, count: 32),
|
||||
@@ -502,4 +509,51 @@ struct ChatPublicConversationCoordinatorContextTests {
|
||||
let unknownHex = String(repeating: "12", count: 32)
|
||||
#expect(coordinator.displayNameForNostrPubkey(unknownHex) == "anon#" + unknownHex.suffix(4))
|
||||
}
|
||||
@Test @MainActor
|
||||
func checkForMentions_postsMentionNotificationOnlyForOthersMentioningMe() async {
|
||||
let context = MockChatPublicConversationContext()
|
||||
let coordinator = ChatPublicConversationCoordinator(context: context)
|
||||
|
||||
// A mention of my nickname from someone else notifies.
|
||||
coordinator.checkForMentions(
|
||||
BitchatMessage(
|
||||
id: "mention-1",
|
||||
sender: "alice",
|
||||
content: "hey @me",
|
||||
timestamp: Date(),
|
||||
isRelay: false,
|
||||
mentions: ["me"]
|
||||
)
|
||||
)
|
||||
#expect(context.mentionNotifications.count == 1)
|
||||
#expect(context.mentionNotifications.first?.sender == "alice")
|
||||
#expect(context.mentionNotifications.first?.message == "hey @me")
|
||||
|
||||
// Mentioning someone else does not notify.
|
||||
coordinator.checkForMentions(
|
||||
BitchatMessage(
|
||||
id: "mention-2",
|
||||
sender: "alice",
|
||||
content: "hey @bob",
|
||||
timestamp: Date(),
|
||||
isRelay: false,
|
||||
mentions: ["bob"]
|
||||
)
|
||||
)
|
||||
#expect(context.mentionNotifications.count == 1)
|
||||
|
||||
// My own message mentioning myself does not notify.
|
||||
coordinator.checkForMentions(
|
||||
BitchatMessage(
|
||||
id: "mention-3",
|
||||
sender: "me",
|
||||
content: "talking about @me",
|
||||
timestamp: Date(),
|
||||
isRelay: false,
|
||||
mentions: ["me"]
|
||||
)
|
||||
)
|
||||
#expect(context.mentionNotifications.count == 1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user