Files
simplex-chat/plans/groups_test_coverage.md
Evgeny 628b00eb08 core: channel messages (#6604)
* core: channel messages (WIP)

* do not include member ID when quoting channel messages

* query plans

* reduce duplication

* refactor

* refactor plan

* refactor 2

* all tests

* remove plan

* refactor 3

* refactor 4

* refactor 5

* refactor 6

* plans

* plans to imrove test coverage and fix bugs

* update plan

* update plan

* bug fixes (wip)

* new plan

* fixes wip

* more tests

* comment, fix lint

* restore comment

* restore comments

* rename param

* move type

* simplify

* comment

* fix stale state

* refactor

* less diff

* simplify

* less diff

* refactor

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2026-02-12 07:11:59 +00:00

18 KiB

Group/Channel Test Coverage Analysis

Coverage run: cabal test simplex-chat-test --enable-coverage --ghc-options=-O0 --test-options="-m group"

Full 164 group tests executed (151 passed, 13 failed due to unrelated issues).

Coverage Summary

After running all group tests:

  • Expressions: 48%
  • Alternatives: 33%
  • Local declarations: 64%
  • Top-level: 34%

What IS Covered (Channel-Specific Paths)

  • createNewRcvChatItem with CDChannelRcv - channel message creation
  • toGroupChatItem with showGroupAsSender = True - channel message reading
  • validSender Nothing CIChannelRcv = True - channel sender validation
  • getGroupChatItemBySharedMsgId with Nothing memberId (IS NOT DISTINCT FROM)
  • toCIDirection CDChannelRcv -> CIChannelRcv
  • toChatInfo CDChannelRcv g s -> GroupChat g s
  • chatItemMember CIChannelRcv -> Nothing
  • viewChatItem for both CIGroupRcv and CIChannelRcv
  • viewItemReaction dispatch to groupReaction for both constructors
  • Channel delete happy path (channelDelete -> delete Nothing)

Uncovered Code Paths

1. Subscriber.hs

processGroupMessage dispatch (lines 935-972)

Line Code Status
956 asGroup == Just True && memberRole' m'' < GROwner tickonlyfalse - rejecting non-owner sending as group never tested
963 ttl parameter in groupMessageUpdate nottickedoff
965 scope_ parameter in groupMsgReaction nottickedoff
967 XFile handler nottickedoff
970 XFileAcptInv handler nottickedoff
987 XGrpPrefs handler nottickedoff
993 BFileChunk handler nottickedoff
994 Catch-all _ for unsupported messages nottickedoff

memberCanSend / memberCanSend' (lines 1446-1454)

Line Code Status
1449 memberPending m part of condition tickonlytrue - never false
1450 otherwise branch (error "member is not allowed to send messages") nottickedoff

newGroupContentMessage (lines 1876-1940)

Line Code Status
1879 vr parameter in mkGetMessageChatScope nottickedoff
1882 ft_ and False parameters to prohibitedGroupContent nottickedoff
1883 rejected helper invocation nottickedoff
1895 mentions parameter for channel messages nottickedoff
1896 pure [] for reactions when sharedMsgId_ is Nothing nottickedoff
1901 rejected function body nottickedoff
1902 Just Nothing for timed_ when forwarded nottickedoff
1910 M.empty for mentions when blocked tickonlyfalse
1914 gInfo' and m' params to processFileInv nottickedoff

groupMessageUpdate (lines 1943-2002)

Line Code Status
1960 Nothing -> pure (CDChannelRcv gInfo Nothing, M.empty, Nothing) nottickedoff - channel catchCINotFound
1967 CDChannelRcv {} -> pure ci' nottickedoff
1977 mentions' = if memberBlocked m then [] tickonlyfalse
1980 otherwise -> messageError "x.msg.update: group member attempted to update..." nottickedoff
1984 messageError "x.msg.update: invalid message update" nottickedoff
2001-2002 CEvtChatItemNotChanged path nottickedoff

groupMessageDelete (lines 2004-2076)

channelDelete path:

Line Code Status
2013 messageError "x.msg.del: invalid channel message delete" nottickedoff
2015 messageError ("x.msg.del: channel message not found, " <> tshow e) nottickedoff

memberDelete path:

Line Code Status
2028 messageError "x.msg.del: member attempted invalid message delete" tickonlyfalse
2036 CIChannelRcv -> messageError "x.msg.del: unexpected channel message..." nottickedoff
2039 messageError ("x.msg.del: message not found, " <> tshow e) tickonlyfalse
2041-2042 messageError "...message of another member with insufficient..." tickonlyfalse
2044-2047 createCIModeration scoped moderation path nottickedoff

moderate helper:

Line Code Status
2058 messageError "x.msg.del: message of another member with incorrect memberId" nottickedoff
2059 messageError "x.msg.del: message of another member without memberId" nottickedoff
2062 messageError "...insufficient member permissions" tickonlyfalse

groupMsgReaction (lines 1818-1860)

Line Code Status
1823-1837 Entire catchCINotFound fallback nottickedoff
1825-1831 Scoped reaction path for member with scope nottickedoff
1832-1834 Regular group reaction when item not found nottickedoff
1835-1837 Channel reaction when item not found nottickedoff
1839 otherwise = pure Nothing when reactions not allowed tickonlyfalse
1859 Nothing return for channel (isJust m_ is False) nottickedoff
1860 pure Nothing when ciReactionAllowed is False nottickedoff

validSender (lines 1871-1874)

Line Code Status
1872 validSender (Just mId) (CIGroupRcv m) = sameMemberId mId m nottickedoff
1873 validSender Nothing CIChannelRcv = True covered
1874 validSender _ _ = False nottickedoff

processForwardedMsg / xGrpMsgForward (lines 3127-3153)

Line Code Status
3133 (const Nothing) wrapper nottickedoff
3139 mentions, msgScope, ttl, live, True to groupMessageUpdate nottickedoff
3141 scope_ and rcvMsg to groupMessageDelete nottickedoff
3143 scope_ to groupMsgReaction nottickedoff
3145 XInfo handler when author_ is Just nottickedoff
3152 XGrpPrefs forwarding nottickedoff
3153 Catch-all error for unsupported forwarded event nottickedoff
3311 FwdChannel -> (Nothing, Nothing) nottickedoff

2. View.hs

viewChatItem (line 646)

Line Code Status
555 groupNtf user g mention - mention parameter for channel nottickedoff
673 showSndItemProhibited to for CISndGroupInvitation nottickedoff
674 showSndItem to fallback for GroupChat nottickedoff
682 CIRcvIntegrityError in group context nottickedoff
683 CIRcvGroupInvitation with isJust m_ guard nottickedoff
684 CIRcvModerated in group context nottickedoff
685 CIRcvBlocked in group context nottickedoff
686 showRcvItem from fallback nottickedoff
691 forwardedFrom in context computation nottickedoff

viewItemUpdate (line 798)

Line Code Status
819 CIGroupRcv m -> updGroupItem (Just m) nottickedoff
822 CIGroupSnd _ -> [] fallback nottickedoff
825 ttyToGroup g scopeInfo (non-edited send path) nottickedoff
830 itemLive == Just True && not liveItems -> [] tickonlyfalse
832 _ -> [] fallback for non-message content nottickedoff
834 ttyFromGroup g scopeInfo m_ (non-edited receive path) nottickedoff
837 forwardedFrom in context nottickedoff
838 groupQuote g in context nottickedoff

viewItemReaction (line 890)

Line Code Status
898-899 sentByMember' g itemDir in both CIGroupRcv and CIChannelRcv nottickedoff
913 groupReaction _ -> [] (non-message-content fallback) nottickedoff
917 else sentBy branch when showGroupAsSender is False nottickedoff
958 sentByMember' function entirely nottickedoff
962 CIChannelRcv -> Nothing in sentByMember' nottickedoff

viewItemDelete (line 869)

Line Code Status
880 _ -> prohibited in GroupChat branch nottickedoff

viewGroupChatItemsDeleted (line 866)

Line Code Status
158 member_ parameter nottickedoff
866 maybe "" (\m -> " " <> ttyMember m) member_ - empty string fallback nottickedoff
- Entire function entirely nottickedoff

groupScopeInfoStr (line 2785)

Line Code Status
- Just (GCSIMemberSupport {groupMember_}) -> ... nottickedoff
- Nothing -> "(support)" sub-branch nottickedoff
- Just m -> "(support: " <> viewMemberName m <> ")" sub-branch nottickedoff

Scope info display

Line Code Status
2768 groupScopeInfoStr scopeInfo in ttyToGroup nottickedoff
2779 groupScopeInfoStr scopeInfo in ttyToGroupEdited nottickedoff
2782 groupScopeInfoStr scopeInfo in fromGroupAttention_ nottickedoff

Other display functions

Line Code Status
625 GroupChat g scopeInfo -> [" " <> ttyToGroup g scopeInfo] nottickedoff
766 (SMDSnd, GroupChat gInfo _scopeInfo) -> Just $ "you #" <> ... nottickedoff
767 (SMDRcv, GroupChat gInfo _scopeInfo) -> Just $ "#" <> ... nottickedoff
936 viewReactionMembers entirely nottickedoff
1020 viewChatCleared GroupChat branch nottickedoff

3. Internal.hs

saveRcvChatItem' (lines 2294-2340)

Line Code Status
2288 M.empty for non-group mentions nottickedoff
2299 groupMentions parameters db and membership nottickedoff
2300 _ -> pure (M.empty, False) for non-group nottickedoff
2303 contactChatDeleted cd tickonlyfalse
2303 vr parameter in updateChatTsStats nottickedoff
2304 else pure $ toChatInfo cd nottickedoff
2316 getRcvCIMentions - db, user, mentions parameters nottickedoff
2319 sameMemberId mId membership in userReply check nottickedoff
2320 \CIMention {memberId} -> sameMemberId memberId membership nottickedoff
2311 createGroupCIMentions db g ci mentions' nottickedoff (mentions always empty)

memberChatStats (line 2323)

Line Code Status
2325-2327 CDGroupRcv _g (Just scope) m -> ... nottickedoff
2328-2329 CDChannelRcv _g (Just scope) -> ... nottickedoff
2330 _ -> Nothing nottickedoff
- Entire function entirely nottickedoff

memberAttentionChange (line 2621)

Line Code Status
- Entire function entirely nottickedoff

getRcvCIMentions (line 277)

Line Code Status
279 not (null ft) && not (null mentions) -> ... nottickedoff
280 uniqueMsgMentions maxRcvMentions mentions $ mentionedNames ft nottickedoff
281 mapM (getMentionedMemberByMemberId db user groupId) mentions' nottickedoff

uniqueMsgMentions (line 286)

Line Code Status
- Entire function entirely nottickedoff

prepareGroupMsg / quoteData (line 204)

Line Code Status
209 MCForward $ ExtMsgContent ... forward branch nottickedoff
227 CIGroupSnd with showGroupAsSender False nottickedoff
228 CIGroupRcv m -> pure (qmc, CIQGroupRcv $ Just m, False, Just m) nottickedoff

mkGetMessageChatScope (lines 1599-1617)

Line Code Status
1601 groupScope@(_gInfo', _m', Just _scopeInfo) -> pure groupScope nottickedoff
1604 isReport mc -> ... tickonlyfalse
1610 sameMemberId mId membership -> ... nottickedoff
1614 otherwise -> do referredMember <- ... nottickedoff
1614 vr parameter in getGroupMemberByMemberId nottickedoff

mkGroupSupportChatInfo (line 1620)

Line Code Status
- Entire function entirely nottickedoff

Feature checks (tickonlyfalse - never true)

Line Code Status
342 isVoice mc && not (groupFeatureMemberAllowed SGFVoice m gInfo) tickonlyfalse
344 isReport mc && ... not (groupFeatureAllowed SGFReports gInfo) tickonlyfalse
485 isACIUserMention deletedChatItem tickonlyfalse
1593 memberPending m tickonlyfalse

sendGroupMessages (line 1986)

Line Code Status
1989 sendProfileUpdate catchAllErrors eToView nottickedoff
1995 isJust scope = False branch nottickedoff

4. Messages.hs

JSON direction functions - ALL ENTIRELY UNTESTED

jsonCIDirection (lines 314-321):

Line Code Status
315 CIDirectSnd -> JCIDirectSnd nottickedoff
316 CIDirectRcv -> JCIDirectRcv nottickedoff
317 CIGroupSnd -> JCIGroupSnd nottickedoff
318 CIGroupRcv m -> JCIGroupRcv m nottickedoff
319 CIChannelRcv -> JCIChannelRcv nottickedoff
320 CILocalSnd -> JCILocalSnd nottickedoff
321 CILocalRcv -> JCILocalRcv nottickedoff

jsonACIDirection (lines 324-331):

Line Code Status
325-331 All branches including JCIChannelRcv -> ACID SCTGroup SMDRcv CIChannelRcv nottickedoff

jsonCIQDirection (lines 646-651):

Line Code Status
647 CIQDirectSnd -> JCIDirectSnd nottickedoff
648 CIQDirectRcv -> JCIDirectRcv nottickedoff
649 CIQGroupSnd -> JCIGroupSnd nottickedoff
650 CIQGroupRcv (Just m) -> JCIGroupRcv m nottickedoff
651 CIQGroupRcv Nothing -> JCIChannelRcv nottickedoff

jsonACIQDirection (lines 654-661):

Line Code Status
655-659 All branches including JCIChannelRcv -> Right $ ACIQDirection SCTGroup $ CIQGroupRcv Nothing nottickedoff
660 JCILocalSnd -> Left "unquotable" nottickedoff
661 JCILocalRcv -> Left "unquotable" nottickedoff

ToJSON/FromJSON instances:

Line Code Status
1469-1470 CIDirection ToJSON nottickedoff
1473 CCIDirection FromJSON nottickedoff
1476 ACIDirection FromJSON nottickedoff
1479 CIQDirection FromJSON nottickedoff
1482-1483 CIQDirection ToJSON nottickedoff

Other Messages.hs functions

Line Code Status
372-375 chatItemRcvFromMember partially covered - _ -> Nothing nottickedoff
403 toCIDirection CDLocalRcv _ -> CILocalRcv nottickedoff
413 toChatInfo CDLocalRcv l -> LocalChat l nottickedoff
486 aChatItemRcvFromMember nottickedoff
665 quoteMsgDirection CIQDirectSnd -> MDSnd nottickedoff
666 quoteMsgDirection CIQDirectRcv -> MDRcv nottickedoff

5. Store/Messages.hs

Scope-filtered query functions - ALL ENTIRELY UNTESTED

Function Lines Status
findGroupChatPreviews_ 862-900 nottickedoff
getChatContentTypes 1183-1197 nottickedoff
getChatItemIDs 1476-1505 nottickedoff
queryUnreadGroupItems 1686-1707 nottickedoff
updateSupportChatItemsRead 2038-2077 nottickedoff
getGroupUnreadTimedItems 2080-2102 nottickedoff
getGroupMemberCIBySharedMsgId 2950-2960 nottickedoff

toGroupChatItem (lines 2327-2337)

Line Code Status
2329 CIChannelRcv with file covered
2332 CIChannelRcv without file covered
2334 CIGroupRcv member with file nottickedoff
2336 CIGroupRcv member without file nottickedoff
2337 badItem fallback nottickedoff
2321 deletedByGroupMember_ parsing nottickedoff

getChatItemQuote_ CDChannelRcv (lines 648-653)

Line Code Status
651 mId == userMemberId check nottickedoff
651 getUserGroupChatItemId_ call nottickedoff
652 otherwise fallback nottickedoff
653 _ -> pure . ciQuote Nothing $ CIQGroupRcv Nothing covered

Reaction functions

Line Code Status
3275 getGroupCIReactions covered
3328 deleteGroupCIReactions_ nottickedoff

Summary

Well-tested channel paths:

  • Channel message create/read/delete happy paths
  • Basic channel reactions
  • Channel quote creation (quoting nothing)
  • validSender Nothing CIChannelRcv
  • getGroupChatItemBySharedMsgId with Nothing memberId

Major gaps:

  1. Non-channel-owner member in channel groups - isChannelOwner always True, memberForChannel = Just m'' never executed

  2. All JSON serialization for CI directions - jsonCIDirection, jsonACIDirection, jsonCIQDirection, jsonACIQDirection and all ToJSON/FromJSON instances entirely untested

  3. Member support scope (GCSIMemberSupport) - mkGroupSupportChatInfo, groupScopeInfoStr, memberChatStats entirely untested

  4. Mentions in channel/group messages - getRcvCIMentions with non-empty mentions, uniqueMsgMentions, createGroupCIMentions never called

  5. Error/fallback paths - catchCINotFound in update/delete/reaction, invalid sender validation, permission errors

  6. Full-delete feature - groupFeatureAllowed SGFFullDelete always false, deleteGroupCIs never called

  7. Live message updates - itemLive == Just True always false

  8. Forwarded message handling - Most parameters to forwarded handlers untested, FwdChannel branch untested

  9. View functions - sentByMember', viewGroupChatItemsDeleted, viewReactionMembers entirely untested

  10. Scope-filtered store queries - 7 functions entirely untested

  11. Feature restriction checks - Voice messages (SGFVoice), reports (SGFReports) feature checks never triggered