2022-01-26 21:20:08 +00:00
{- # LANGUAGE DuplicateRecordFields # -}
2021-07-24 10:26:28 +01:00
{- # LANGUAGE NamedFieldPuns # -}
2021-07-07 22:46:38 +01:00
{- # LANGUAGE OverloadedStrings # -}
2021-08-02 20:10:24 +01:00
{- # LANGUAGE PostfixOperators # -}
2021-07-07 22:46:38 +01:00
module ChatTests where
import ChatClient
2022-03-05 20:32:29 +04:00
import Control.Concurrent ( threadDelay )
2021-07-07 22:46:38 +01:00
import Control.Concurrent.Async ( concurrently_ )
import Control.Concurrent.STM
2021-09-04 07:32:56 +01:00
import qualified Data.ByteString as B
2021-07-07 22:46:38 +01:00
import Data.Char ( isDigit )
2021-07-24 10:26:28 +01:00
import qualified Data.Text as T
2022-02-09 20:58:02 +04:00
import Simplex.Chat.Controller ( ChatController ( .. ) )
2022-04-24 09:05:54 +01:00
import Simplex.Chat.Types ( ConnStatus ( .. ) , ImageData ( .. ) , Profile ( .. ) , User ( .. ) )
2021-09-04 07:32:56 +01:00
import Simplex.Chat.Util ( unlessM )
2022-04-15 13:16:34 +01:00
import System.Directory ( copyFile , doesFileExist )
2021-07-07 22:46:38 +01:00
import Test.Hspec
aliceProfile :: Profile
2022-03-10 15:45:40 +04:00
aliceProfile = Profile { displayName = " alice " , fullName = " Alice " , image = Nothing }
2021-07-07 22:46:38 +01:00
bobProfile :: Profile
2022-04-04 19:51:49 +01:00
bobProfile = Profile { displayName = " bob " , fullName = " Bob " , image = Just ( ImageData " data:image/png;base64,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
2021-07-07 22:46:38 +01:00
2021-07-24 10:26:28 +01:00
cathProfile :: Profile
2022-03-10 15:45:40 +04:00
cathProfile = Profile { displayName = " cath " , fullName = " Catherine " , image = Nothing }
2021-07-24 10:26:28 +01:00
danProfile :: Profile
2022-03-10 15:45:40 +04:00
danProfile = Profile { displayName = " dan " , fullName = " Daniel " , image = Nothing }
2021-07-24 10:26:28 +01:00
2021-07-16 07:40:55 +01:00
chatTests :: Spec
chatTests = do
2022-03-13 19:34:03 +00:00
describe " direct messages " $ do
2021-07-16 07:40:55 +01:00
it " add contact and send/receive message " testAddContact
2022-03-13 19:34:03 +00:00
it " direct message quoted replies " testDirectMessageQuotedReply
2022-03-23 11:37:51 +00:00
it " direct message update " testDirectMessageUpdate
2022-03-28 20:35:57 +04:00
it " direct message delete " testDirectMessageDelete
2021-07-24 10:26:28 +01:00
describe " chat groups " $ do
2021-07-16 07:40:55 +01:00
it " add contacts, create group and send/receive messages " testGroup
2021-07-24 10:26:28 +01:00
it " create and join group with 4 members " testGroup2
2021-08-02 20:10:24 +01:00
it " create and delete group " testGroupDelete
2022-01-05 20:46:35 +04:00
it " invitee delete group when in status invited " testGroupDeleteWhenInvited
2022-01-06 23:39:58 +04:00
it " re-add member in status invited " testGroupReAddInvited
2021-08-05 08:38:39 +01:00
it " remove contact from group and add again " testGroupRemoveAdd
2022-01-06 23:39:58 +04:00
it " list groups containing group invitations " testGroupList
2022-03-13 19:34:03 +00:00
it " group message quoted replies " testGroupMessageQuotedReply
2022-03-23 11:37:51 +00:00
it " group message update " testGroupMessageUpdate
2022-03-28 20:35:57 +04:00
it " group message delete " testGroupMessageDelete
2022-03-10 15:45:40 +04:00
describe " user profiles " $ do
2021-08-22 15:56:36 +01:00
it " update user profiles and notify contacts " testUpdateProfile
2022-03-10 15:45:40 +04:00
it " update user profile with image " testUpdateProfileImage
2021-09-04 07:32:56 +01:00
describe " sending and receiving files " $ do
it " send and receive file " testFileTransfer
2021-09-25 10:09:49 +01:00
it " send and receive a small file " testSmallFileTransfer
2021-09-04 07:32:56 +01:00
it " sender cancelled file transfer " testFileSndCancel
it " recipient cancelled file transfer " testFileRcvCancel
2021-09-05 14:08:29 +01:00
it " send and receive file to group " testGroupFileTransfer
2022-04-10 13:30:58 +04:00
describe " messages with files " $ do
it " send and receive message with file " testMessageWithFile
it " send and receive image " testSendImage
2022-04-15 13:16:34 +01:00
it " files folder: send and receive image " testFilesFoldersSendImage
it " files folder: sender deleted file during transfer " testFilesFoldersImageSndDelete
it " files folder: recipient deleted file during transfer " testFilesFoldersImageRcvDelete
2022-04-10 13:30:58 +04:00
it " send and receive image with text and quote " testSendImageWithTextAndQuote
it " send and receive image to group " testGroupSendImage
it " send and receive image with text and quote to group " testGroupSendImageWithTextAndQuote
2021-12-08 13:09:51 +00:00
describe " user contact link " $ do
2022-03-10 15:45:40 +04:00
it " create and connect via contact link " testUserContactLink
it " auto accept contact requests " testUserContactLinkAutoAccept
it " deduplicate contact requests " testDeduplicateContactRequests
it " deduplicate contact requests with profile change " testDeduplicateContactRequestsProfileChange
it " reject contact and delete contact link " testRejectContactAndDeleteUserContact
it " delete connection requests when contact link deleted " testDeleteConnectionRequests
2022-03-13 19:34:03 +00:00
describe " SMP servers " $
it " get and set SMP servers " testGetSetSMPServers
2022-04-26 12:52:41 +04:00
describe " async connection handshake " $ do
it " connect when initiating client goes offline " testAsyncInitiatingOffline
it " connect when accepting client goes offline " testAsyncAcceptingOffline
it " connect, fully asynchronous (when clients are never simultaneously online) " testFullAsync
xdescribe " async sending and receiving files " $ do
it " send and receive file, fully asynchronous " testAsyncFileTransfer
it " send and receive file to group, fully asynchronous " testAsyncGroupFileTransfer
2021-07-16 07:40:55 +01:00
testAddContact :: IO ()
testAddContact =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
2021-08-02 20:10:24 +01:00
alice ##> " /c "
2021-08-05 20:51:48 +01:00
inv <- getInvitation alice
2021-07-07 22:46:38 +01:00
bob ##> ( " /c " <> inv )
2021-12-11 12:57:12 +00:00
bob <## " confirmation sent! "
2021-07-07 22:46:38 +01:00
concurrently_
2021-08-02 20:10:24 +01:00
( bob <## " alice (Alice): contact is connected " )
( alice <## " bob (Bob): contact is connected " )
2022-03-13 19:34:03 +00:00
chatsEmpty alice bob
2022-02-04 12:41:43 +00:00
alice #> " @bob hello 🙂 "
bob <# " alice> hello 🙂 "
2022-03-13 19:34:03 +00:00
chatsOneMessage alice bob
2021-07-07 22:46:38 +01:00
bob #> " @alice hi "
alice <# " bob> hi "
2022-03-13 19:34:03 +00:00
chatsManyMessages alice bob
2021-07-14 20:11:41 +01:00
-- test adding the same contact one more time - local name will be different
2021-08-02 20:10:24 +01:00
alice ##> " /c "
2021-08-05 20:51:48 +01:00
inv' <- getInvitation alice
2021-07-14 20:11:41 +01:00
bob ##> ( " /c " <> inv' )
2021-12-11 12:57:12 +00:00
bob <## " confirmation sent! "
2021-07-14 20:11:41 +01:00
concurrently_
2021-08-02 20:10:24 +01:00
( bob <## " alice_1 (Alice): contact is connected " )
( alice <## " bob_1 (Bob): contact is connected " )
2021-07-14 20:11:41 +01:00
alice #> " @bob_1 hello "
bob <# " alice_1> hello "
bob #> " @alice_1 hi "
alice <# " bob_1> hi "
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob_1 " , " hi " ) , ( " @bob " , " hi " ) ]
bob @@@ [ ( " @alice_1 " , " hi " ) , ( " @alice " , " hi " ) ]
2021-07-14 20:11:41 +01:00
-- test deleting contact
alice ##> " /d bob_1 "
2021-08-02 20:10:24 +01:00
alice <## " bob_1: contact is deleted "
2022-01-24 16:07:17 +00:00
alice ##> " @bob_1 hey "
2021-07-14 20:11:41 +01:00
alice <## " no contact bob_1 "
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " hi " ) ]
bob @@@ [ ( " @alice_1 " , " hi " ) , ( " @alice " , " hi " ) ]
2022-03-13 19:34:03 +00:00
where
chatsEmpty alice bob = do
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " " ) ]
2022-03-13 19:34:03 +00:00
alice #$> ( " /_get chat @2 count=100 " , chat , [] )
2022-04-23 18:23:29 +01:00
bob @@@ [ ( " @alice " , " " ) ]
2022-03-13 19:34:03 +00:00
bob #$> ( " /_get chat @2 count=100 " , chat , [] )
chatsOneMessage alice bob = do
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " hello 🙂 " ) ]
2022-03-13 19:34:03 +00:00
alice #$> ( " /_get chat @2 count=100 " , chat , [ ( 1 , " hello 🙂 " ) ] )
2022-04-23 18:23:29 +01:00
bob @@@ [ ( " @alice " , " hello 🙂 " ) ]
2022-03-13 19:34:03 +00:00
bob #$> ( " /_get chat @2 count=100 " , chat , [ ( 0 , " hello 🙂 " ) ] )
chatsManyMessages alice bob = do
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " hi " ) ]
2022-03-13 19:34:03 +00:00
alice #$> ( " /_get chat @2 count=100 " , chat , [ ( 1 , " hello 🙂 " ) , ( 0 , " hi " ) ] )
2022-04-23 18:23:29 +01:00
bob @@@ [ ( " @alice " , " hi " ) ]
2022-03-13 19:34:03 +00:00
bob #$> ( " /_get chat @2 count=100 " , chat , [ ( 0 , " hello 🙂 " ) , ( 1 , " hi " ) ] )
-- pagination
alice #$> ( " /_get chat @2 after=1 count=100 " , chat , [ ( 0 , " hi " ) ] )
alice #$> ( " /_get chat @2 before=2 count=100 " , chat , [ ( 1 , " hello 🙂 " ) ] )
-- read messages
alice #$> ( " /_read chat @2 from=1 to=100 " , id , " ok " )
bob #$> ( " /_read chat @2 from=1 to=100 " , id , " ok " )
2021-07-07 22:46:38 +01:00
2022-03-13 19:34:03 +00:00
testDirectMessageQuotedReply :: IO ()
2022-03-28 20:35:57 +04:00
testDirectMessageQuotedReply =
2022-03-10 15:45:40 +04:00
testChat2 aliceProfile bobProfile $
2022-03-13 19:34:03 +00:00
\ alice bob -> do
connectUsers alice bob
alice ##> " /_send @2 json { \ " type \ " : \ " text \ " , \ " text \ " : \ " hello! how are you? \ " } "
alice <# " @bob hello! how are you? "
bob <# " alice> hello! how are you? "
bob #> " @alice hi! "
alice <# " bob> hi! "
bob ` send ` " > @alice (hello) all good - you? "
bob <# " @alice > hello! how are you? "
bob <## " all good - you? "
alice <# " bob> > hello! how are you? "
alice <## " all good - you? "
2022-03-16 13:20:47 +00:00
bob #$> ( " /_get chat @2 count=1 " , chat' , [ ( ( 1 , " all good - you? " ) , Just ( 0 , " hello! how are you? " ) ) ] )
alice #$> ( " /_get chat @2 count=1 " , chat' , [ ( ( 0 , " all good - you? " ) , Just ( 1 , " hello! how are you? " ) ) ] )
2022-03-13 19:34:03 +00:00
bob ` send ` " >> @alice (all good) will tell more "
bob <# " @alice >> all good - you? "
bob <## " will tell more "
alice <# " bob> >> all good - you? "
alice <## " will tell more "
2022-03-16 13:20:47 +00:00
bob #$> ( " /_get chat @2 count=1 " , chat' , [ ( ( 1 , " will tell more " ) , Just ( 1 , " all good - you? " ) ) ] )
alice #$> ( " /_get chat @2 count=1 " , chat' , [ ( ( 0 , " will tell more " ) , Just ( 0 , " all good - you? " ) ) ] )
2022-03-10 15:45:40 +04:00
2022-03-23 11:37:51 +00:00
testDirectMessageUpdate :: IO ()
2022-03-28 20:35:57 +04:00
testDirectMessageUpdate =
2022-03-23 11:37:51 +00:00
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
-- msg id 1
alice #> " @bob hello 🙂 "
bob <# " alice> hello 🙂 "
-- msg id 2
bob ` send ` " > @alice (hello) hi alice "
bob <# " @alice > hello 🙂 "
bob <## " hi alice "
alice <# " bob> > hello 🙂 "
alice <## " hi alice "
alice #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 1 , " hello 🙂 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 1 , " hello 🙂 " ) ) ] )
bob #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 0 , " hello 🙂 " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hello 🙂 " ) ) ] )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_update item @2 1 text hey 👋 " , id , " message updated " )
2022-03-23 11:37:51 +00:00
bob <# " alice> [edited] hey 👋 "
alice #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 1 , " hey 👋 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 1 , " hello 🙂 " ) ) ] )
bob #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 0 , " hey 👋 " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hello 🙂 " ) ) ] )
-- msg id 3
bob ` send ` " > @alice (hey) hey alice "
bob <# " @alice > hey 👋 "
bob <## " hey alice "
alice <# " bob> > hey 👋 "
alice <## " hey alice "
alice #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 1 , " hey 👋 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 1 , " hello 🙂 " ) ) , ( ( 0 , " hey alice " ) , Just ( 1 , " hey 👋 " ) ) ] )
bob #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 0 , " hey 👋 " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hello 🙂 " ) ) , ( ( 1 , " hey alice " ) , Just ( 0 , " hey 👋 " ) ) ] )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_update item @2 1 text greetings 🤝 " , id , " message updated " )
2022-03-23 11:37:51 +00:00
bob <# " alice> [edited] greetings 🤝 "
2022-03-28 20:35:57 +04:00
alice #$> ( " /_update item @2 2 text updating bob's message " , id , " cannot update this item " )
2022-03-23 11:37:51 +00:00
alice #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 1 , " greetings 🤝 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 1 , " hello 🙂 " ) ) , ( ( 0 , " hey alice " ) , Just ( 1 , " hey 👋 " ) ) ] )
bob #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 0 , " greetings 🤝 " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hello 🙂 " ) ) , ( ( 1 , " hey alice " ) , Just ( 0 , " hey 👋 " ) ) ] )
2022-04-03 09:44:23 +01:00
bob #$> ( " /_update item @2 2 text hey Alice " , id , " message updated " )
2022-03-23 11:37:51 +00:00
alice <# " bob> [edited] > hello 🙂 "
alice <## " hey Alice "
2022-04-03 09:44:23 +01:00
bob #$> ( " /_update item @2 3 text greetings Alice " , id , " message updated " )
2022-03-23 11:37:51 +00:00
alice <# " bob> [edited] > hey 👋 "
alice <## " greetings Alice "
alice #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 1 , " greetings 🤝 " ) , Nothing ) , ( ( 0 , " hey Alice " ) , Just ( 1 , " hello 🙂 " ) ) , ( ( 0 , " greetings Alice " ) , Just ( 1 , " hey 👋 " ) ) ] )
bob #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 0 , " greetings 🤝 " ) , Nothing ) , ( ( 1 , " hey Alice " ) , Just ( 0 , " hello 🙂 " ) ) , ( ( 1 , " greetings Alice " ) , Just ( 0 , " hey 👋 " ) ) ] )
2022-03-28 20:35:57 +04:00
testDirectMessageDelete :: IO ()
testDirectMessageDelete =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
-- msg id 1
alice #> " @bob hello 🙂 "
bob <# " alice> hello 🙂 "
-- msg id 2
bob ` send ` " > @alice (hello) hey alic "
bob <# " @alice > hello 🙂 "
bob <## " hey alic "
alice <# " bob> > hello 🙂 "
alice <## " hey alic "
2022-04-03 09:44:23 +01:00
alice #$> ( " /_delete item @2 1 internal " , id , " message deleted " )
alice #$> ( " /_delete item @2 2 internal " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " " ) ]
2022-03-28 20:35:57 +04:00
alice #$> ( " /_get chat @2 count=100 " , chat , [] )
alice #$> ( " /_update item @2 1 text updating deleted message " , id , " cannot update this item " )
2022-04-10 13:30:58 +04:00
alice #$> ( " /_send @2 quoted 1 text quoting deleted message " , id , " cannot reply to this message " )
2022-03-28 20:35:57 +04:00
2022-04-03 09:44:23 +01:00
bob #$> ( " /_update item @2 2 text hey alice " , id , " message updated " )
2022-03-28 20:35:57 +04:00
alice <# " bob> [edited] hey alice "
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " hey alice " ) ]
2022-03-28 20:35:57 +04:00
alice #$> ( " /_get chat @2 count=100 " , chat , [ ( 0 , " hey alice " ) ] )
-- msg id 3
bob #> " @alice how are you? "
alice <# " bob> how are you? "
2022-04-03 09:44:23 +01:00
bob #$> ( " /_delete item @2 3 broadcast " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
alice <# " bob> [deleted] how are you? "
2022-04-03 09:44:23 +01:00
alice #$> ( " /_delete item @2 1 broadcast " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
bob <# " alice> [deleted] hello 🙂 "
alice #$> ( " /_delete item @2 2 broadcast " , id , " cannot delete this item " )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_delete item @2 2 internal " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " this item is deleted (broadcast) " ) ]
2022-03-28 20:35:57 +04:00
alice #$> ( " /_get chat @2 count=100 " , chat , [ ( 0 , " this item is deleted (broadcast) " ) ] )
2022-04-23 18:23:29 +01:00
bob @@@ [ ( " @alice " , " hey alice " ) ]
2022-03-28 20:35:57 +04:00
bob #$> ( " /_get chat @2 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) , ( ( 1 , " hey alice " ) , ( Just ( 0 , " hello 🙂 " ) ) ) ] )
2021-07-16 07:40:55 +01:00
testGroup :: IO ()
testGroup =
2021-07-24 10:26:28 +01:00
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
2021-07-16 07:40:55 +01:00
connectUsers alice bob
2021-07-24 10:26:28 +01:00
connectUsers alice cath
2021-08-05 20:51:48 +01:00
alice ##> " /g team "
alice <## " group #team is created "
alice <## " use /a team <name> to add members "
2021-07-24 10:26:28 +01:00
alice ##> " /a team bob "
2021-08-05 20:51:48 +01:00
concurrentlyN_
[ alice <## " invitation to join the group #team sent to bob " ,
do
bob <## " #team: alice invites you to join the group as admin "
bob <## " use /j team to accept "
]
2021-07-24 10:26:28 +01:00
bob ##> " /j team "
concurrently_
( alice <## " #team: bob joined the group " )
( bob <## " #team: you joined the group " )
alice ##> " /a team cath "
2021-08-05 20:51:48 +01:00
concurrentlyN_
[ alice <## " invitation to join the group #team sent to cath " ,
do
cath <## " #team: alice invites you to join the group as admin "
cath <## " use /j team to accept "
]
2021-07-24 10:26:28 +01:00
cath ##> " /j team "
concurrentlyN_
[ alice <## " #team: cath joined the group " ,
do
cath <## " #team: you joined the group "
cath <## " #team: member bob (Bob) is connected " ,
do
bob <## " #team: alice added cath (Catherine) to the group (connecting...) "
bob <## " #team: new member cath is connected "
]
alice #> " #team hello "
concurrently_
( bob <# " #team alice> hello " )
( cath <# " #team alice> hello " )
2022-03-05 20:32:29 +04:00
threadDelay 1000000 -- server assigns timestamps with one second precision
2021-07-24 10:26:28 +01:00
bob #> " #team hi there "
2021-07-16 07:40:55 +01:00
concurrently_
2021-07-24 10:26:28 +01:00
( alice <# " #team bob> hi there " )
( cath <# " #team bob> hi there " )
2022-03-05 20:32:29 +04:00
threadDelay 1000000
2022-02-09 20:58:02 +04:00
cath #> " #team hey team "
2021-07-24 10:26:28 +01:00
concurrently_
2022-02-09 20:58:02 +04:00
( alice <# " #team cath> hey team " )
( bob <# " #team cath> hey team " )
2021-08-02 20:10:24 +01:00
bob <##> cath
2022-03-13 19:34:03 +00:00
getReadChats alice bob cath
2021-12-10 11:45:58 +00:00
-- list groups
alice ##> " /gs "
alice <## " #team "
-- list group members
alice ##> " /ms team "
alice
<### [ " alice (Alice): owner, you, created group " ,
" bob (Bob): admin, invited, connected " ,
" cath (Catherine): admin, invited, connected "
]
-- list contacts
alice ##> " /cs "
alice <## " bob (Bob) "
alice <## " cath (Catherine) "
2021-08-02 20:10:24 +01:00
-- remove member
bob ##> " /rm team cath "
concurrentlyN_
[ bob <## " #team: you removed cath from the group " ,
alice <## " #team: bob removed cath from the group " ,
2021-08-05 20:51:48 +01:00
do
cath <## " #team: bob removed you from the group "
cath <## " use /d #team to delete the group "
2021-08-02 20:10:24 +01:00
]
bob #> " #team hi "
concurrently_
( alice <# " #team bob> hi " )
( cath </ )
alice #> " #team hello "
concurrently_
( bob <# " #team alice> hello " )
( cath </ )
2022-01-24 16:07:17 +00:00
cath ##> " #team hello "
2022-01-05 20:46:35 +04:00
cath <## " you are no longer a member of the group "
2021-08-02 20:10:24 +01:00
bob <##> cath
2022-03-13 19:34:03 +00:00
where
getReadChats alice bob cath = do
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " #team " , " hey team " ) , ( " @cath " , " " ) , ( " @bob " , " " ) ]
2022-03-13 19:34:03 +00:00
alice #$> ( " /_get chat #1 count=100 " , chat , [ ( 1 , " hello " ) , ( 0 , " hi there " ) , ( 0 , " hey team " ) ] )
alice #$> ( " /_get chat #1 after=1 count=100 " , chat , [ ( 0 , " hi there " ) , ( 0 , " hey team " ) ] )
alice #$> ( " /_get chat #1 before=3 count=100 " , chat , [ ( 1 , " hello " ) , ( 0 , " hi there " ) ] )
2022-04-23 18:23:29 +01:00
bob @@@ [ ( " @cath " , " hey " ) , ( " #team " , " hey team " ) , ( " @alice " , " " ) ]
2022-03-13 19:34:03 +00:00
bob #$> ( " /_get chat #1 count=100 " , chat , [ ( 0 , " hello " ) , ( 1 , " hi there " ) , ( 0 , " hey team " ) ] )
2022-04-23 18:23:29 +01:00
cath @@@ [ ( " @bob " , " hey " ) , ( " #team " , " hey team " ) , ( " @alice " , " " ) ]
2022-03-13 19:34:03 +00:00
cath #$> ( " /_get chat #1 count=100 " , chat , [ ( 0 , " hello " ) , ( 0 , " hi there " ) , ( 1 , " hey team " ) ] )
alice #$> ( " /_read chat #1 from=1 to=100 " , id , " ok " )
bob #$> ( " /_read chat #1 from=1 to=100 " , id , " ok " )
cath #$> ( " /_read chat #1 from=1 to=100 " , id , " ok " )
2021-07-24 10:26:28 +01:00
testGroup2 :: IO ()
testGroup2 =
testChat4 aliceProfile bobProfile cathProfile danProfile $
\ alice bob cath dan -> do
connectUsers alice bob
connectUsers alice cath
connectUsers bob dan
connectUsers alice dan
2021-08-05 20:51:48 +01:00
alice ##> " /g club "
alice <## " group #club is created "
alice <## " use /a club <name> to add members "
2021-07-24 10:26:28 +01:00
alice ##> " /a club bob "
2021-08-05 20:51:48 +01:00
concurrentlyN_
[ alice <## " invitation to join the group #club sent to bob " ,
do
bob <## " #club: alice invites you to join the group as admin "
bob <## " use /j club to accept "
]
2021-07-24 10:26:28 +01:00
alice ##> " /a club cath "
2021-08-05 20:51:48 +01:00
concurrentlyN_
[ alice <## " invitation to join the group #club sent to cath " ,
do
cath <## " #club: alice invites you to join the group as admin "
cath <## " use /j club to accept "
]
2021-07-24 10:26:28 +01:00
bob ##> " /j club "
concurrently_
( alice <## " #club: bob joined the group " )
( bob <## " #club: you joined the group " )
cath ##> " /j club "
concurrentlyN_
[ alice <## " #club: cath joined the group " ,
do
cath <## " #club: you joined the group "
cath <## " #club: member bob (Bob) is connected " ,
do
bob <## " #club: alice added cath (Catherine) to the group (connecting...) "
bob <## " #club: new member cath is connected "
]
bob ##> " /a club dan "
2021-08-05 20:51:48 +01:00
concurrentlyN_
[ bob <## " invitation to join the group #club sent to dan " ,
do
dan <## " #club: bob invites you to join the group as admin "
dan <## " use /j club to accept "
]
2021-07-24 10:26:28 +01:00
dan ##> " /j club "
concurrentlyN_
[ bob <## " #club: dan joined the group " ,
do
dan <## " #club: you joined the group "
2021-08-05 20:51:48 +01:00
dan
<### [ " #club: member alice_1 (Alice) is connected " ,
" contact alice_1 is merged into alice " ,
" use @alice <message> to send messages " ,
" #club: member cath (Catherine) is connected "
] ,
2021-07-24 10:26:28 +01:00
do
alice <## " #club: bob added dan_1 (Daniel) to the group (connecting...) "
2021-07-27 08:08:05 +01:00
alice <## " #club: new member dan_1 is connected "
2021-08-05 20:51:48 +01:00
alice <## " contact dan_1 is merged into dan "
alice <## " use @dan <message> to send messages " ,
2021-07-24 10:26:28 +01:00
do
cath <## " #club: bob added dan (Daniel) to the group (connecting...) "
cath <## " #club: new member dan is connected "
]
alice #> " #club hello "
concurrentlyN_
[ bob <# " #club alice> hello " ,
cath <# " #club alice> hello " ,
2021-07-27 08:08:05 +01:00
dan <# " #club alice> hello "
2021-07-24 10:26:28 +01:00
]
bob #> " #club hi there "
concurrentlyN_
[ alice <# " #club bob> hi there " ,
cath <# " #club bob> hi there " ,
dan <# " #club bob> hi there "
]
cath #> " #club hey "
concurrentlyN_
[ alice <# " #club cath> hey " ,
bob <# " #club cath> hey " ,
dan <# " #club cath> hey "
]
dan #> " #club how is it going? "
concurrentlyN_
2021-07-27 08:08:05 +01:00
[ alice <# " #club dan> how is it going? " ,
2021-07-24 10:26:28 +01:00
bob <# " #club dan> how is it going? " ,
cath <# " #club dan> how is it going? "
]
2021-08-02 20:10:24 +01:00
bob <##> cath
dan <##> cath
dan <##> alice
2022-04-30 21:23:14 +01:00
-- show last messages
alice ##> " /t #club 3 "
alice <# " #club cath> hey "
alice <# " #club dan> how is it going? "
alice <# " #club hello "
alice ##> " /t @dan 2 "
alice <# " dan> hi "
alice <# " @dan hey "
alice ##> " /t 5 "
2022-05-01 14:07:18 +01:00
alice -- these strings are expected in any order because of sorting by time
<##? [ " #club cath> hey " ,
" #club dan> how is it going? " ,
" #club hello " ,
" dan> hi " ,
" @dan hey "
]
2021-08-02 20:10:24 +01:00
-- remove member
cath ##> " /rm club dan "
concurrentlyN_
[ cath <## " #club: you removed dan from the group " ,
alice <## " #club: cath removed dan from the group " ,
bob <## " #club: cath removed dan from the group " ,
2021-08-05 20:51:48 +01:00
do
dan <## " #club: cath removed you from the group "
dan <## " use /d #club to delete the group "
2021-08-02 20:10:24 +01:00
]
alice #> " #club hello "
concurrentlyN_
[ bob <# " #club alice> hello " ,
cath <# " #club alice> hello " ,
( dan </ )
]
bob #> " #club hi there "
concurrentlyN_
[ alice <# " #club bob> hi there " ,
cath <# " #club bob> hi there " ,
( dan </ )
]
cath #> " #club hey "
concurrentlyN_
[ alice <# " #club cath> hey " ,
bob <# " #club cath> hey " ,
( dan </ )
]
2022-01-24 16:07:17 +00:00
dan ##> " #club how is it going? "
2022-01-05 20:46:35 +04:00
dan <## " you are no longer a member of the group "
2022-01-12 16:32:22 +00:00
dan ##> " /d #club "
dan <## " #club: you deleted the group "
2021-08-02 20:10:24 +01:00
dan <##> cath
dan <##> alice
-- member leaves
bob ##> " /l club "
concurrentlyN_
2021-08-05 20:51:48 +01:00
[ do
bob <## " #club: you left the group "
bob <## " use /d #club to delete the group " ,
2021-08-02 20:10:24 +01:00
alice <## " #club: bob left the group " ,
cath <## " #club: bob left the group "
]
alice #> " #club hello "
concurrently_
( cath <# " #club alice> hello " )
( bob </ )
cath #> " #club hey "
concurrently_
( alice <# " #club cath> hey " )
( bob </ )
2022-01-24 16:07:17 +00:00
bob ##> " #club how is it going? "
2022-01-05 20:46:35 +04:00
bob <## " you are no longer a member of the group "
2022-01-12 16:32:22 +00:00
bob ##> " /d #club "
bob <## " #club: you deleted the group "
2021-08-02 20:10:24 +01:00
bob <##> cath
bob <##> alice
testGroupDelete :: IO ()
testGroupDelete =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
alice ##> " /d #team "
concurrentlyN_
[ alice <## " #team: you deleted the group " ,
2021-08-05 20:51:48 +01:00
do
bob <## " #team: alice deleted the group "
bob <## " use /d #team to delete the local copy of the group " ,
do
cath <## " #team: alice deleted the group "
cath <## " use /d #team to delete the local copy of the group "
2021-08-02 20:10:24 +01:00
]
2022-02-02 23:50:43 +04:00
alice ##> " #team hi "
alice <## " no group #team "
2021-08-05 20:51:48 +01:00
bob ##> " /d #team "
2021-08-02 20:10:24 +01:00
bob <## " #team: you deleted the group "
2022-01-24 16:07:17 +00:00
cath ##> " #team hi "
2022-01-05 20:46:35 +04:00
cath <## " you are no longer a member of the group "
2022-01-12 16:32:22 +00:00
cath ##> " /d #team "
cath <## " #team: you deleted the group "
2022-01-05 20:46:35 +04:00
testGroupDeleteWhenInvited :: IO ()
testGroupDeleteWhenInvited =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice ##> " /g team "
alice <## " group #team is created "
alice <## " use /a team <name> to add members "
alice ##> " /a team bob "
concurrentlyN_
[ alice <## " invitation to join the group #team sent to bob " ,
do
bob <## " #team: alice invites you to join the group as admin "
bob <## " use /j team to accept "
]
bob ##> " /d #team "
bob <## " #team: you deleted the group "
2022-01-06 23:39:58 +04:00
-- alice doesn't receive notification that bob deleted group,
-- but she can re-add bob
2022-01-05 20:46:35 +04:00
alice ##> " /a team bob "
2022-01-06 23:39:58 +04:00
concurrentlyN_
[ alice <## " invitation to join the group #team sent to bob " ,
do
bob <## " #team: alice invites you to join the group as admin "
bob <## " use /j team to accept "
]
testGroupReAddInvited :: IO ()
testGroupReAddInvited =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice ##> " /g team "
alice <## " group #team is created "
alice <## " use /a team <name> to add members "
2022-01-05 20:46:35 +04:00
alice ##> " /a team bob "
concurrentlyN_
[ alice <## " invitation to join the group #team sent to bob " ,
do
bob <## " #team: alice invites you to join the group as admin "
bob <## " use /j team to accept "
]
2022-01-06 23:39:58 +04:00
-- alice re-adds bob, he sees it as the same group
alice ##> " /a team bob "
concurrentlyN_
[ alice <## " invitation to join the group #team sent to bob " ,
do
bob <## " #team: alice invites you to join the group as admin "
bob <## " use /j team to accept "
]
-- if alice removes bob and then re-adds him, she uses a new connection request
-- and he sees it as a new group with a different local display name
alice ##> " /rm team bob "
alice <## " #team: you removed bob from the group "
alice ##> " /a team bob "
concurrentlyN_
[ alice <## " invitation to join the group #team sent to bob " ,
do
bob <## " #team_1 (team): alice invites you to join the group as admin "
bob <## " use /j team_1 to accept "
]
2021-08-02 20:10:24 +01:00
testGroupRemoveAdd :: IO ()
testGroupRemoveAdd =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
-- remove member
alice ##> " /rm team bob "
concurrentlyN_
[ alice <## " #team: you removed bob from the group " ,
2021-08-05 20:51:48 +01:00
do
bob <## " #team: alice removed you from the group "
bob <## " use /d #team to delete the group " ,
2021-08-02 20:10:24 +01:00
cath <## " #team: alice removed bob from the group "
]
alice ##> " /a team bob "
2021-08-05 20:51:48 +01:00
alice <## " invitation to join the group #team sent to bob "
bob <## " #team_1 (team): alice invites you to join the group as admin "
bob <## " use /j team_1 to accept "
2021-08-02 20:10:24 +01:00
bob ##> " /j team_1 "
concurrentlyN_
[ alice <## " #team: bob joined the group " ,
do
bob <## " #team_1: you joined the group "
bob <## " #team_1: member cath_1 (Catherine) is connected "
2021-08-05 20:51:48 +01:00
bob <## " contact cath_1 is merged into cath "
bob <## " use @cath <message> to send messages " ,
2021-08-02 20:10:24 +01:00
do
cath <## " #team: alice added bob_1 (Bob) to the group (connecting...) "
cath <## " #team: new member bob_1 is connected "
2021-08-05 20:51:48 +01:00
cath <## " contact bob_1 is merged into bob "
cath <## " use @bob <message> to send messages "
2021-08-02 20:10:24 +01:00
]
alice #> " #team hi "
concurrently_
( bob <# " #team_1 alice> hi " )
( cath <# " #team alice> hi " )
bob #> " #team_1 hey "
concurrently_
( alice <# " #team bob> hey " )
( cath <# " #team bob> hey " )
cath #> " #team hello "
concurrently_
( alice <# " #team cath> hello " )
( bob <# " #team_1 cath> hello " )
2021-07-16 07:40:55 +01:00
2022-01-06 13:09:03 +04:00
testGroupList :: IO ()
testGroupList =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
createGroup2 " team " alice bob
alice ##> " /g tennis "
alice <## " group #tennis is created "
alice <## " use /a tennis <name> to add members "
alice ##> " /a tennis bob "
concurrentlyN_
[ alice <## " invitation to join the group #tennis sent to bob " ,
do
bob <## " #tennis: alice invites you to join the group as admin "
bob <## " use /j tennis to accept "
]
-- alice sees both groups
alice ##> " /gs "
alice <### [ " #team " , " #tennis " ]
-- bob sees #tennis as invitation
bob ##> " /gs "
bob
<### [ " #team " ,
" #tennis - you are invited (/j tennis to join, /d #tennis to delete invitation) "
]
-- after deleting invitation bob sees only one group
bob ##> " /d #tennis "
bob <## " #tennis: you deleted the group "
bob ##> " /gs "
bob <## " #team "
2022-03-13 19:34:03 +00:00
testGroupMessageQuotedReply :: IO ()
testGroupMessageQuotedReply =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
alice #> " #team hello! how are you? "
concurrently_
( bob <# " #team alice> hello! how are you? " )
( cath <# " #team alice> hello! how are you? " )
2022-03-16 13:20:47 +00:00
threadDelay 1000000
2022-03-13 19:34:03 +00:00
bob ` send ` " > #team @alice (hello) hello, all good, you? "
bob <# " #team > alice hello! how are you? "
bob <## " hello, all good, you? "
concurrently_
( do
alice <# " #team bob> > alice hello! how are you? "
alice <## " hello, all good, you? "
)
( do
cath <# " #team bob> > alice hello! how are you? "
cath <## " hello, all good, you? "
)
2022-03-16 13:20:47 +00:00
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hello! how are you? " ) , Nothing ) , ( ( 1 , " hello, all good, you? " ) , Just ( 0 , " hello! how are you? " ) ) ] )
alice #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 1 , " hello! how are you? " ) , Nothing ) , ( ( 0 , " hello, all good, you? " ) , Just ( 1 , " hello! how are you? " ) ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hello! how are you? " ) , Nothing ) , ( ( 0 , " hello, all good, you? " ) , Just ( 0 , " hello! how are you? " ) ) ] )
2022-03-13 19:34:03 +00:00
bob ` send ` " > #team bob (hello, all good) will tell more "
bob <# " #team > bob hello, all good, you? "
bob <## " will tell more "
concurrently_
( do
alice <# " #team bob> > bob hello, all good, you? "
alice <## " will tell more "
)
( do
cath <# " #team bob> > bob hello, all good, you? "
cath <## " will tell more "
)
2022-03-16 13:20:47 +00:00
bob #$> ( " /_get chat #1 count=1 " , chat' , [ ( ( 1 , " will tell more " ) , Just ( 1 , " hello, all good, you? " ) ) ] )
alice #$> ( " /_get chat #1 count=1 " , chat' , [ ( ( 0 , " will tell more " ) , Just ( 0 , " hello, all good, you? " ) ) ] )
cath #$> ( " /_get chat #1 count=1 " , chat' , [ ( ( 0 , " will tell more " ) , Just ( 0 , " hello, all good, you? " ) ) ] )
threadDelay 1000000
2022-03-13 19:34:03 +00:00
cath ` send ` " > #team bob (hello) hi there! "
cath <# " #team > bob hello, all good, you? "
cath <## " hi there! "
concurrently_
( do
alice <# " #team cath> > bob hello, all good, you? "
alice <## " hi there! "
)
( do
bob <# " #team cath> > bob hello, all good, you? "
bob <## " hi there! "
)
2022-03-16 13:20:47 +00:00
cath #$> ( " /_get chat #1 count=1 " , chat' , [ ( ( 1 , " hi there! " ) , Just ( 0 , " hello, all good, you? " ) ) ] )
alice #$> ( " /_get chat #1 count=1 " , chat' , [ ( ( 0 , " hi there! " ) , Just ( 0 , " hello, all good, you? " ) ) ] )
bob #$> ( " /_get chat #1 count=1 " , chat' , [ ( ( 0 , " hi there! " ) , Just ( 1 , " hello, all good, you? " ) ) ] )
2022-03-23 11:37:51 +00:00
alice ` send ` " > #team (will tell) go on "
2022-03-19 09:04:53 +00:00
alice <# " #team > bob will tell more "
alice <## " go on "
concurrently_
( do
bob <# " #team alice> > bob will tell more "
bob <## " go on "
)
( do
cath <# " #team alice> > bob will tell more "
cath <## " go on "
)
2022-03-13 19:34:03 +00:00
2022-03-23 11:37:51 +00:00
testGroupMessageUpdate :: IO ()
2022-03-28 20:35:57 +04:00
testGroupMessageUpdate =
2022-03-23 11:37:51 +00:00
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
2022-03-28 20:35:57 +04:00
-- msg id 1
2022-03-23 11:37:51 +00:00
alice #> " #team hello! "
concurrently_
( bob <# " #team alice> hello! " )
( cath <# " #team alice> hello! " )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_update item #1 1 text hey 👋 " , id , " message updated " )
2022-03-23 11:37:51 +00:00
concurrently_
( bob <# " #team alice> [edited] hey 👋 " )
( cath <# " #team alice> [edited] hey 👋 " )
alice #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 1 , " hey 👋 " ) , Nothing ) ] )
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hey 👋 " ) , Nothing ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hey 👋 " ) , Nothing ) ] )
threadDelay 1000000
2022-03-28 20:35:57 +04:00
-- msg id 2
2022-03-23 11:37:51 +00:00
bob ` send ` " > #team @alice (hey) hi alice "
bob <# " #team > alice hey 👋 "
bob <## " hi alice "
concurrently_
( do
alice <# " #team bob> > alice hey 👋 "
alice <## " hi alice "
)
( do
cath <# " #team bob> > alice hey 👋 "
cath <## " hi alice "
)
alice #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 1 , " hey 👋 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 1 , " hey 👋 " ) ) ] )
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hey 👋 " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hey 👋 " ) ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hey 👋 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 0 , " hey 👋 " ) ) ] )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_update item #1 1 text greetings 🤝 " , id , " message updated " )
2022-03-23 11:37:51 +00:00
concurrently_
( bob <# " #team alice> [edited] greetings 🤝 " )
( cath <# " #team alice> [edited] greetings 🤝 " )
2022-03-28 20:35:57 +04:00
alice #$> ( " /_update item #1 2 text updating bob's message " , id , " cannot update this item " )
2022-03-23 11:37:51 +00:00
threadDelay 1000000
cath ` send ` " > #team @alice (greetings) greetings! "
cath <# " #team > alice greetings 🤝 "
cath <## " greetings! "
concurrently_
( do
alice <# " #team cath> > alice greetings 🤝 "
alice <## " greetings! "
)
( do
bob <# " #team cath> > alice greetings 🤝 "
bob <## " greetings! "
)
alice #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 1 , " greetings 🤝 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 1 , " hey 👋 " ) ) , ( ( 0 , " greetings! " ) , Just ( 1 , " greetings 🤝 " ) ) ] )
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " greetings 🤝 " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hey 👋 " ) ) , ( ( 0 , " greetings! " ) , Just ( 0 , " greetings 🤝 " ) ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " greetings 🤝 " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 0 , " hey 👋 " ) ) , ( ( 1 , " greetings! " ) , Just ( 0 , " greetings 🤝 " ) ) ] )
2022-03-28 20:35:57 +04:00
testGroupMessageDelete :: IO ()
testGroupMessageDelete =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
-- msg id 1
alice #> " #team hello! "
concurrently_
( bob <# " #team alice> hello! " )
( cath <# " #team alice> hello! " )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_delete item #1 1 internal " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
alice #$> ( " /_get chat #1 count=100 " , chat , [] )
bob #$> ( " /_get chat #1 count=100 " , chat , [ ( 0 , " hello! " ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat , [ ( 0 , " hello! " ) ] )
alice #$> ( " /_update item #1 1 text updating deleted message " , id , " cannot update this item " )
2022-04-10 13:30:58 +04:00
alice #$> ( " /_send #1 quoted 1 text quoting deleted message " , id , " cannot reply to this message " )
2022-03-28 20:35:57 +04:00
threadDelay 1000000
-- msg id 2
bob ` send ` " > #team @alice (hello) hi alic "
bob <# " #team > alice hello! "
bob <## " hi alic "
concurrently_
( do
alice <# " #team bob> > alice hello! "
alice <## " hi alic "
)
( do
cath <# " #team bob> > alice hello! "
cath <## " hi alic "
)
alice #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hi alic " ) , Just ( 1 , " hello! " ) ) ] )
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hello! " ) , Nothing ) , ( ( 1 , " hi alic " ) , Just ( 0 , " hello! " ) ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hello! " ) , Nothing ) , ( ( 0 , " hi alic " ) , Just ( 0 , " hello! " ) ) ] )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_delete item #1 1 broadcast " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
concurrently_
( bob <# " #team alice> [deleted] hello! " )
( cath <# " #team alice> [deleted] hello! " )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_delete item #1 2 internal " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
alice #$> ( " /_get chat #1 count=100 " , chat' , [] )
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) , ( ( 1 , " hi alic " ) , Just ( 0 , " hello! " ) ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) , ( ( 0 , " hi alic " ) , Just ( 0 , " hello! " ) ) ] )
2022-04-03 09:44:23 +01:00
bob #$> ( " /_update item #1 2 text hi alice " , id , " message updated " )
2022-03-28 20:35:57 +04:00
concurrently_
( alice <# " #team bob> [edited] hi alice " )
( do
cath <# " #team bob> [edited] > alice hello! "
cath <## " hi alice "
)
alice #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " hi alice " ) , Nothing ) ] )
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hello! " ) ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 0 , " hello! " ) ) ] )
threadDelay 1000000
-- msg id 3
cath #> " #team how are you? "
concurrently_
( alice <# " #team cath> how are you? " )
( bob <# " #team cath> how are you? " )
2022-04-03 09:44:23 +01:00
cath #$> ( " /_delete item #1 3 broadcast " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
concurrently_
( alice <# " #team cath> [deleted] how are you? " )
( bob <# " #team cath> [deleted] how are you? " )
alice #$> ( " /_delete item #1 2 broadcast " , id , " cannot delete this item " )
2022-04-03 09:44:23 +01:00
alice #$> ( " /_delete item #1 2 internal " , id , " message deleted " )
2022-03-28 20:35:57 +04:00
alice #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) ] )
bob #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) , ( ( 1 , " hi alice " ) , Just ( 0 , " hello! " ) ) , ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) ] )
cath #$> ( " /_get chat #1 count=100 " , chat' , [ ( ( 0 , " this item is deleted (broadcast) " ) , Nothing ) , ( ( 0 , " hi alice " ) , Just ( 0 , " hello! " ) ) ] )
2021-08-22 15:56:36 +01:00
testUpdateProfile :: IO ()
testUpdateProfile =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
alice ##> " /p "
alice <## " user profile: alice (Alice) "
2021-09-04 07:32:56 +01:00
alice <## " use /p <display name> [<full name>] to change it "
2021-08-22 15:56:36 +01:00
alice <## " (the updated profile will be sent to all your contacts) "
alice ##> " /p alice "
concurrentlyN_
[ alice <## " user full name removed (your contacts are notified) " ,
bob <## " contact alice removed full name " ,
cath <## " contact alice removed full name "
]
alice ##> " /p alice Alice Jones "
concurrentlyN_
[ alice <## " user full name changed to Alice Jones (your contacts are notified) " ,
bob <## " contact alice updated full name: Alice Jones " ,
cath <## " contact alice updated full name: Alice Jones "
]
cath ##> " /p cate "
concurrentlyN_
[ cath <## " user profile is changed to cate (your contacts are notified) " ,
do
alice <## " contact cath changed to cate "
alice <## " use @cate <message> to send messages " ,
do
bob <## " contact cath changed to cate "
bob <## " use @cate <message> to send messages "
]
cath ##> " /p cat Cate "
concurrentlyN_
[ cath <## " user profile is changed to cat (Cate) (your contacts are notified) " ,
do
alice <## " contact cate changed to cat (Cate) "
alice <## " use @cat <message> to send messages " ,
do
bob <## " contact cate changed to cat (Cate) "
bob <## " use @cat <message> to send messages "
]
2022-03-10 15:45:40 +04:00
testUpdateProfileImage :: IO ()
testUpdateProfileImage =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice ##> " /profile_image data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= "
alice <## " profile image updated "
2022-03-19 07:42:54 +00:00
alice ##> " /profile_image "
alice <## " profile image removed "
2022-03-23 20:52:00 +00:00
alice ##> " /_profile { \ " displayName \ " : \ " alice2 \ " , \ " fullName \ " : \ " \ " } "
alice <## " user profile is changed to alice2 (your contacts are notified) "
bob <## " contact alice changed to alice2 "
bob <## " use @alice2 <message> to send messages "
2022-03-10 15:45:40 +04:00
( bob </ )
2021-09-04 07:32:56 +01:00
testFileTransfer :: IO ()
testFileTransfer =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
startFileTransfer alice bob
concurrentlyN_
[ do
bob #> " @alice receiving here... "
2021-09-05 14:08:29 +01:00
bob <## " completed receiving file 1 (test.jpg) from alice " ,
2021-09-04 07:32:56 +01:00
do
alice <# " bob> receiving here... "
2021-09-05 14:08:29 +01:00
alice <## " completed sending file 1 (test.jpg) to bob "
2021-09-04 07:32:56 +01:00
]
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
2021-09-25 10:09:49 +01:00
testSmallFileTransfer :: IO ()
testSmallFileTransfer =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice #> " /f @bob ./tests/fixtures/test.txt "
alice <## " use /fc 1 to cancel sending "
bob <# " alice> sends file test.txt (11 bytes / 11 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 ./tests/tmp "
bob <## " saving file 1 from alice to ./tests/tmp/test.txt "
concurrentlyN_
[ do
bob <## " started receiving file 1 (test.txt) from alice "
bob <## " completed receiving file 1 (test.txt) from alice " ,
do
alice <## " started sending file 1 (test.txt) to bob "
alice <## " completed sending file 1 (test.txt) to bob "
]
src <- B . readFile " ./tests/fixtures/test.txt "
dest <- B . readFile " ./tests/tmp/test.txt "
dest ` shouldBe ` src
2021-09-04 07:32:56 +01:00
testFileSndCancel :: IO ()
testFileSndCancel =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
startFileTransfer alice bob
alice ##> " /fc 1 "
concurrentlyN_
[ do
2021-09-05 14:08:29 +01:00
alice <## " cancelled sending file 1 (test.jpg) to bob "
2021-09-04 07:32:56 +01:00
alice ##> " /fs 1 "
2022-04-05 10:01:08 +04:00
alice <## " sending file 1 (test.jpg) cancelled: bob "
alice <## " file transfer cancelled " ,
2021-09-04 07:32:56 +01:00
do
2021-09-05 14:08:29 +01:00
bob <## " alice cancelled sending file 1 (test.jpg) "
2021-09-04 07:32:56 +01:00
bob ##> " /fs 1 "
2021-09-05 14:08:29 +01:00
bob <## " receiving file 1 (test.jpg) cancelled, received part path: ./tests/tmp/test.jpg "
2021-09-04 07:32:56 +01:00
]
checkPartialTransfer
testFileRcvCancel :: IO ()
testFileRcvCancel =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
startFileTransfer alice bob
bob ##> " /fs 1 "
2021-09-05 14:08:29 +01:00
getTermLine bob >>= ( ` shouldStartWith ` " receiving file 1 (test.jpg) progress " )
2021-09-04 07:32:56 +01:00
waitFileExists " ./tests/tmp/test.jpg "
bob ##> " /fc 1 "
concurrentlyN_
[ do
2021-09-05 14:08:29 +01:00
bob <## " cancelled receiving file 1 (test.jpg) from alice "
2021-09-04 07:32:56 +01:00
bob ##> " /fs 1 "
2021-09-05 14:08:29 +01:00
bob <## " receiving file 1 (test.jpg) cancelled, received part path: ./tests/tmp/test.jpg " ,
2021-09-04 07:32:56 +01:00
do
2021-09-05 14:08:29 +01:00
alice <## " bob cancelled receiving file 1 (test.jpg) "
2021-09-04 07:32:56 +01:00
alice ##> " /fs 1 "
2022-04-05 10:01:08 +04:00
alice <## " sending file 1 (test.jpg) cancelled: bob "
2021-09-04 07:32:56 +01:00
]
checkPartialTransfer
2021-09-05 14:08:29 +01:00
testGroupFileTransfer :: IO ()
testGroupFileTransfer =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
alice #> " /f #team ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
concurrentlyN_
[ do
bob <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it " ,
do
cath <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
cath <## " use /fr 1 [<dir>/ | <path>] to receive it "
]
alice ##> " /fs 1 "
2022-04-05 10:01:08 +04:00
getTermLine alice >>= ( ` shouldStartWith ` " sending file 1 (test.jpg): no file transfers " )
bob ##> " /fr 1 ./tests/tmp/ "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
concurrentlyN_
[ do
alice <## " started sending file 1 (test.jpg) to bob "
alice <## " completed sending file 1 (test.jpg) to bob "
alice ##> " /fs 1 "
alice <## " sending file 1 (test.jpg) complete: bob " ,
do
bob <## " started receiving file 1 (test.jpg) from alice "
bob <## " completed receiving file 1 (test.jpg) from alice "
]
cath ##> " /fr 1 ./tests/tmp/ "
cath <## " saving file 1 from alice to ./tests/tmp/test_1.jpg "
concurrentlyN_
[ do
alice <## " started sending file 1 (test.jpg) to cath "
alice <## " completed sending file 1 (test.jpg) to cath "
alice ##> " /fs 1 "
getTermLine alice >>= ( ` shouldStartWith ` " sending file 1 (test.jpg) complete " ) ,
do
cath <## " started receiving file 1 (test.jpg) from alice "
cath <## " completed receiving file 1 (test.jpg) from alice "
]
2022-04-10 13:30:58 +04:00
testMessageWithFile :: IO ()
testMessageWithFile =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice ##> " /_send @2 file ./tests/fixtures/test.jpg text hi, sending a file "
alice <# " @bob hi, sending a file "
alice <# " /f @bob ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
bob <# " alice> hi, sending a file "
bob <# " alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 ./tests/tmp "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
concurrently_
( bob <## " started receiving file 1 (test.jpg) from alice " )
( alice <## " started sending file 1 (test.jpg) to bob " )
concurrently_
( bob <## " completed receiving file 1 (test.jpg) from alice " )
( alice <## " completed sending file 1 (test.jpg) to bob " )
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
alice #$> ( " /_get chat @2 count=100 " , chatF , [ ( ( 1 , " hi, sending a file " ) , Just " ./tests/fixtures/test.jpg " ) ] )
bob #$> ( " /_get chat @2 count=100 " , chatF , [ ( ( 0 , " hi, sending a file " ) , Just " ./tests/tmp/test.jpg " ) ] )
testSendImage :: IO ()
testSendImage =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice ##> " /_send @2 file ./tests/fixtures/test.jpg json { \ " text \ " : \ " \ " , \ " type \ " : \ " image \ " , \ " image \ " : \ " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= \ " } "
alice <# " /f @bob ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
bob <# " alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 ./tests/tmp "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
concurrently_
( bob <## " started receiving file 1 (test.jpg) from alice " )
( alice <## " started sending file 1 (test.jpg) to bob " )
concurrently_
( bob <## " completed receiving file 1 (test.jpg) from alice " )
( alice <## " completed sending file 1 (test.jpg) to bob " )
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
alice #$> ( " /_get chat @2 count=100 " , chatF , [ ( ( 1 , " " ) , Just " ./tests/fixtures/test.jpg " ) ] )
bob #$> ( " /_get chat @2 count=100 " , chatF , [ ( ( 0 , " " ) , Just " ./tests/tmp/test.jpg " ) ] )
2022-04-15 09:36:38 +04:00
-- deleting contact without files folder set should not remove file
bob ##> " /d alice "
bob <## " alice: contact is deleted "
fileExists <- doesFileExist " ./tests/tmp/test.jpg "
fileExists ` shouldBe ` True
2022-04-15 13:16:34 +01:00
testFilesFoldersSendImage :: IO ()
testFilesFoldersSendImage =
2022-04-15 09:36:38 +04:00
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice #$> ( " /_files_folder ./tests/fixtures " , id , " ok " )
2022-04-15 13:16:34 +01:00
bob #$> ( " /_files_folder ./tests/tmp/app_files " , id , " ok " )
2022-04-15 09:36:38 +04:00
alice ##> " /_send @2 file test.jpg json { \ " text \ " : \ " \ " , \ " type \ " : \ " image \ " , \ " image \ " : \ " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= \ " } "
alice <# " /f @bob test.jpg "
alice <## " use /fc 1 to cancel sending "
bob <# " alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 "
bob <## " saving file 1 from alice to test.jpg "
concurrently_
( bob <## " started receiving file 1 (test.jpg) from alice " )
( alice <## " started sending file 1 (test.jpg) to bob " )
concurrently_
( bob <## " completed receiving file 1 (test.jpg) from alice " )
( alice <## " completed sending file 1 (test.jpg) to bob " )
src <- B . readFile " ./tests/fixtures/test.jpg "
2022-04-15 13:16:34 +01:00
dest <- B . readFile " ./tests/tmp/app_files/test.jpg "
2022-04-15 09:36:38 +04:00
dest ` shouldBe ` src
alice #$> ( " /_get chat @2 count=100 " , chatF , [ ( ( 1 , " " ) , Just " test.jpg " ) ] )
bob #$> ( " /_get chat @2 count=100 " , chatF , [ ( ( 0 , " " ) , Just " test.jpg " ) ] )
-- deleting contact with files folder set should remove file
2022-04-15 13:16:34 +01:00
checkActionDeletesFile " ./tests/tmp/app_files/test.jpg " $ do
bob ##> " /d alice "
bob <## " alice: contact is deleted "
testFilesFoldersImageSndDelete :: IO ()
testFilesFoldersImageSndDelete =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice #$> ( " /_files_folder ./tests/tmp/alice_app_files " , id , " ok " )
2022-04-26 11:51:46 +04:00
copyFile " ./tests/fixtures/test_1MB.pdf " " ./tests/tmp/alice_app_files/test_1MB.pdf "
2022-04-15 13:16:34 +01:00
bob #$> ( " /_files_folder ./tests/tmp/bob_app_files " , id , " ok " )
2022-04-26 11:51:46 +04:00
alice ##> " /_send @2 file test_1MB.pdf json { \ " text \ " : \ " \ " , \ " type \ " : \ " image \ " , \ " image \ " : \ " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= \ " } "
alice <# " /f @bob test_1MB.pdf "
2022-04-15 13:16:34 +01:00
alice <## " use /fc 1 to cancel sending "
2022-04-26 11:51:46 +04:00
bob <# " alice> sends file test_1MB.pdf (1017.7 KiB / 1042157 bytes) "
2022-04-15 13:16:34 +01:00
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 "
2022-04-26 11:51:46 +04:00
bob <## " saving file 1 from alice to test_1MB.pdf "
2022-04-15 13:16:34 +01:00
concurrently_
2022-04-26 11:51:46 +04:00
( bob <## " started receiving file 1 (test_1MB.pdf) from alice " )
( alice <## " started sending file 1 (test_1MB.pdf) to bob " )
2022-04-15 13:16:34 +01:00
-- deleting contact should cancel and remove file
2022-04-26 11:51:46 +04:00
checkActionDeletesFile " ./tests/tmp/alice_app_files/test_1MB.pdf " $ do
2022-04-15 13:16:34 +01:00
alice ##> " /d bob "
alice <## " bob: contact is deleted "
2022-04-26 11:51:46 +04:00
bob <## " alice cancelled sending file 1 (test_1MB.pdf) "
2022-04-15 13:16:34 +01:00
bob ##> " /fs 1 "
2022-04-26 11:51:46 +04:00
bob <## " receiving file 1 (test_1MB.pdf) cancelled, received part path: test_1MB.pdf "
2022-04-15 13:16:34 +01:00
-- deleting contact should remove cancelled file
2022-04-26 11:51:46 +04:00
checkActionDeletesFile " ./tests/tmp/bob_app_files/test_1MB.pdf " $ do
2022-04-15 13:16:34 +01:00
bob ##> " /d alice "
bob <## " alice: contact is deleted "
testFilesFoldersImageRcvDelete :: IO ()
testFilesFoldersImageRcvDelete =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
alice #$> ( " /_files_folder ./tests/fixtures " , id , " ok " )
bob #$> ( " /_files_folder ./tests/tmp/app_files " , id , " ok " )
alice ##> " /_send @2 file test.jpg json { \ " text \ " : \ " \ " , \ " type \ " : \ " image \ " , \ " image \ " : \ " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= \ " } "
alice <# " /f @bob test.jpg "
alice <## " use /fc 1 to cancel sending "
bob <# " alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 "
bob <## " saving file 1 from alice to test.jpg "
concurrently_
( bob <## " started receiving file 1 (test.jpg) from alice " )
( alice <## " started sending file 1 (test.jpg) to bob " )
-- deleting contact should cancel and remove file
waitFileExists " ./tests/tmp/app_files/test.jpg "
checkActionDeletesFile " ./tests/tmp/app_files/test.jpg " $ do
bob ##> " /d alice "
bob <## " alice: contact is deleted "
alice <## " bob cancelled receiving file 1 (test.jpg) "
alice ##> " /fs 1 "
alice <## " sending file 1 (test.jpg) cancelled: bob "
2022-04-10 13:30:58 +04:00
testSendImageWithTextAndQuote :: IO ()
testSendImageWithTextAndQuote =
testChat2 aliceProfile bobProfile $
\ alice bob -> do
connectUsers alice bob
bob #> " @alice hi alice "
alice <# " bob> hi alice "
alice ##> " /_send @2 file ./tests/fixtures/test.jpg quoted 1 json { \ " text \ " : \ " hey bob \ " , \ " type \ " : \ " image \ " , \ " image \ " : \ " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= \ " } "
alice <# " @bob > hi alice "
alice <## " hey bob "
alice <# " /f @bob ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
bob <# " alice> > hi alice "
bob <## " hey bob "
bob <# " alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 ./tests/tmp "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
concurrently_
( bob <## " started receiving file 1 (test.jpg) from alice " )
( alice <## " started sending file 1 (test.jpg) to bob " )
concurrently_
( bob <## " completed receiving file 1 (test.jpg) from alice " )
( alice <## " completed sending file 1 (test.jpg) to bob " )
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
alice #$> ( " /_get chat @2 count=100 " , chat'' , [ ( ( 0 , " hi alice " ) , Nothing , Nothing ) , ( ( 1 , " hey bob " ) , Just ( 0 , " hi alice " ) , Just " ./tests/fixtures/test.jpg " ) ] )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " hey bob " ) ]
2022-04-10 13:30:58 +04:00
bob #$> ( " /_get chat @2 count=100 " , chat'' , [ ( ( 1 , " hi alice " ) , Nothing , Nothing ) , ( ( 0 , " hey bob " ) , Just ( 1 , " hi alice " ) , Just " ./tests/tmp/test.jpg " ) ] )
2022-04-23 18:23:29 +01:00
bob @@@ [ ( " @alice " , " hey bob " ) ]
2022-04-10 13:30:58 +04:00
testGroupSendImage :: IO ()
testGroupSendImage =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
alice ##> " /_send #1 file ./tests/fixtures/test.jpg json { \ " text \ " : \ " \ " , \ " type \ " : \ " image \ " , \ " image \ " : \ " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= \ " } "
alice <# " /f #team ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
concurrentlyN_
[ do
bob <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it " ,
do
cath <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
cath <## " use /fr 1 [<dir>/ | <path>] to receive it "
]
bob ##> " /fr 1 ./tests/tmp/ "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
concurrentlyN_
[ do
alice <## " started sending file 1 (test.jpg) to bob "
alice <## " completed sending file 1 (test.jpg) to bob " ,
do
bob <## " started receiving file 1 (test.jpg) from alice "
bob <## " completed receiving file 1 (test.jpg) from alice "
]
cath ##> " /fr 1 ./tests/tmp/ "
cath <## " saving file 1 from alice to ./tests/tmp/test_1.jpg "
concurrentlyN_
[ do
alice <## " started sending file 1 (test.jpg) to cath "
alice <## " completed sending file 1 (test.jpg) to cath " ,
do
cath <## " started receiving file 1 (test.jpg) from alice "
cath <## " completed receiving file 1 (test.jpg) from alice "
]
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
dest2 <- B . readFile " ./tests/tmp/test_1.jpg "
dest2 ` shouldBe ` src
alice #$> ( " /_get chat #1 count=100 " , chatF , [ ( ( 1 , " " ) , Just " ./tests/fixtures/test.jpg " ) ] )
bob #$> ( " /_get chat #1 count=100 " , chatF , [ ( ( 0 , " " ) , Just " ./tests/tmp/test.jpg " ) ] )
cath #$> ( " /_get chat #1 count=100 " , chatF , [ ( ( 0 , " " ) , Just " ./tests/tmp/test_1.jpg " ) ] )
testGroupSendImageWithTextAndQuote :: IO ()
testGroupSendImageWithTextAndQuote =
testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
createGroup3 " team " alice bob cath
bob #> " #team hi team "
concurrently_
( alice <# " #team bob> hi team " )
( cath <# " #team bob> hi team " )
threadDelay 1000000
alice ##> " /_send #1 file ./tests/fixtures/test.jpg quoted 1 json { \ " text \ " : \ " hey bob \ " , \ " type \ " : \ " image \ " , \ " image \ " : \ " data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII= \ " } "
alice <# " #team > bob hi team "
alice <## " hey bob "
alice <# " /f #team ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
concurrentlyN_
[ do
bob <# " #team alice> > bob hi team "
bob <## " hey bob "
bob <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it " ,
do
cath <# " #team alice> > bob hi team "
cath <## " hey bob "
cath <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
cath <## " use /fr 1 [<dir>/ | <path>] to receive it "
]
bob ##> " /fr 1 ./tests/tmp/ "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
concurrentlyN_
[ do
alice <## " started sending file 1 (test.jpg) to bob "
alice <## " completed sending file 1 (test.jpg) to bob " ,
do
bob <## " started receiving file 1 (test.jpg) from alice "
bob <## " completed receiving file 1 (test.jpg) from alice "
]
cath ##> " /fr 1 ./tests/tmp/ "
cath <## " saving file 1 from alice to ./tests/tmp/test_1.jpg "
concurrentlyN_
[ do
alice <## " started sending file 1 (test.jpg) to cath "
alice <## " completed sending file 1 (test.jpg) to cath " ,
do
cath <## " started receiving file 1 (test.jpg) from alice "
cath <## " completed receiving file 1 (test.jpg) from alice "
]
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
dest2 <- B . readFile " ./tests/tmp/test_1.jpg "
dest2 ` shouldBe ` src
alice #$> ( " /_get chat #1 count=100 " , chat'' , [ ( ( 0 , " hi team " ) , Nothing , Nothing ) , ( ( 1 , " hey bob " ) , Just ( 0 , " hi team " ) , Just " ./tests/fixtures/test.jpg " ) ] )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " #team " , " hey bob " ) , ( " @bob " , " " ) , ( " @cath " , " " ) ]
2022-04-10 13:30:58 +04:00
bob #$> ( " /_get chat #1 count=100 " , chat'' , [ ( ( 1 , " hi team " ) , Nothing , Nothing ) , ( ( 0 , " hey bob " ) , Just ( 1 , " hi team " ) , Just " ./tests/tmp/test.jpg " ) ] )
2022-04-23 18:23:29 +01:00
bob @@@ [ ( " #team " , " hey bob " ) , ( " @alice " , " " ) , ( " @cath " , " " ) ]
2022-04-10 13:30:58 +04:00
cath #$> ( " /_get chat #1 count=100 " , chat'' , [ ( ( 0 , " hi team " ) , Nothing , Nothing ) , ( ( 0 , " hey bob " ) , Just ( 0 , " hi team " ) , Just " ./tests/tmp/test_1.jpg " ) ] )
2022-04-23 18:23:29 +01:00
cath @@@ [ ( " #team " , " hey bob " ) , ( " @alice " , " " ) , ( " @bob " , " " ) ]
2022-04-10 13:30:58 +04:00
2021-12-08 13:09:51 +00:00
testUserContactLink :: IO ()
testUserContactLink = testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
alice ##> " /ad "
cLink <- getContactLink alice True
bob ##> ( " /c " <> cLink )
alice <#? bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@bob " , " " ) ]
2021-12-08 13:09:51 +00:00
alice ##> " /ac bob "
2022-02-13 13:19:24 +04:00
alice <## " bob (Bob): accepting contact request... "
2021-12-08 13:09:51 +00:00
concurrently_
( bob <## " alice (Alice): contact is connected " )
( alice <## " bob (Bob): contact is connected " )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " " ) ]
2021-12-08 13:09:51 +00:00
alice <##> bob
cath ##> ( " /c " <> cLink )
alice <#? cath
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@cath " , " " ) , ( " @bob " , " hey " ) ]
2021-12-08 13:09:51 +00:00
alice ##> " /ac cath "
2022-02-13 13:19:24 +04:00
alice <## " cath (Catherine): accepting contact request... "
2021-12-08 13:09:51 +00:00
concurrently_
( cath <## " alice (Alice): contact is connected " )
( alice <## " cath (Catherine): contact is connected " )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @cath " , " " ) , ( " @bob " , " hey " ) ]
2021-12-08 13:09:51 +00:00
alice <##> cath
2022-02-14 14:59:11 +04:00
testUserContactLinkAutoAccept :: IO ()
testUserContactLinkAutoAccept =
testChat4 aliceProfile bobProfile cathProfile danProfile $
\ alice bob cath dan -> do
alice ##> " /ad "
cLink <- getContactLink alice True
bob ##> ( " /c " <> cLink )
alice <#? bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@bob " , " " ) ]
2022-02-14 14:59:11 +04:00
alice ##> " /ac bob "
alice <## " bob (Bob): accepting contact request... "
concurrently_
( bob <## " alice (Alice): contact is connected " )
( alice <## " bob (Bob): contact is connected " )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " " ) ]
2022-02-14 14:59:11 +04:00
alice <##> bob
alice ##> " /auto_accept on "
alice <## " auto_accept on "
cath ##> ( " /c " <> cLink )
cath <## " connection request sent! "
alice <## " cath (Catherine): accepting contact request... "
concurrently_
( cath <## " alice (Alice): contact is connected " )
( alice <## " cath (Catherine): contact is connected " )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @cath " , " " ) , ( " @bob " , " hey " ) ]
2022-02-14 14:59:11 +04:00
alice <##> cath
alice ##> " /auto_accept off "
alice <## " auto_accept off "
dan ##> ( " /c " <> cLink )
alice <#? dan
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@dan " , " " ) , ( " @cath " , " hey " ) , ( " @bob " , " hey " ) ]
2022-02-14 14:59:11 +04:00
alice ##> " /ac dan "
alice <## " dan (Daniel): accepting contact request... "
concurrently_
( dan <## " alice (Alice): contact is connected " )
( alice <## " dan (Daniel): contact is connected " )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @dan " , " " ) , ( " @cath " , " hey " ) , ( " @bob " , " hey " ) ]
2022-02-14 14:59:11 +04:00
alice <##> dan
2022-02-13 13:19:24 +04:00
testDeduplicateContactRequests :: IO ()
testDeduplicateContactRequests = testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
alice ##> " /ad "
cLink <- getContactLink alice True
bob ##> ( " /c " <> cLink )
alice <#? bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@bob " , " " ) ]
2022-04-24 09:05:54 +01:00
bob @@@! [ ( " :1 " , " " , Just ConnJoined ) ]
2022-02-13 13:19:24 +04:00
bob ##> ( " /c " <> cLink )
alice <#? bob
bob ##> ( " /c " <> cLink )
alice <#? bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@bob " , " " ) ]
2022-04-24 09:05:54 +01:00
bob @@@! [ ( " :3 " , " " , Just ConnJoined ) , ( " :2 " , " " , Just ConnJoined ) , ( " :1 " , " " , Just ConnJoined ) ]
2022-02-13 13:19:24 +04:00
alice ##> " /ac bob "
alice <## " bob (Bob): accepting contact request... "
concurrently_
( bob <## " alice (Alice): contact is connected " )
( alice <## " bob (Bob): contact is connected " )
bob ##> ( " /c " <> cLink )
bob <## " alice (Alice): contact already exists "
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " " ) ]
2022-04-24 09:05:54 +01:00
bob @@@ [ ( " @alice " , " " ) , ( " :2 " , " " ) , ( " :1 " , " " ) ]
bob ##> " /_delete :1 "
bob <## " connection :1 deleted "
bob ##> " /_delete :2 "
bob <## " connection :2 deleted "
2022-02-13 13:19:24 +04:00
alice <##> bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @bob " , " hey " ) ]
bob @@@ [ ( " @alice " , " hey " ) ]
2022-02-13 13:19:24 +04:00
bob ##> ( " /c " <> cLink )
bob <## " alice (Alice): contact already exists "
alice <##> bob
alice #$> ( " /_get chat @2 count=100 " , chat , [ ( 1 , " hi " ) , ( 0 , " hey " ) , ( 1 , " hi " ) , ( 0 , " hey " ) ] )
bob #$> ( " /_get chat @2 count=100 " , chat , [ ( 0 , " hi " ) , ( 1 , " hey " ) , ( 0 , " hi " ) , ( 1 , " hey " ) ] )
cath ##> ( " /c " <> cLink )
alice <#? cath
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@cath " , " " ) , ( " @bob " , " hey " ) ]
2022-02-13 13:19:24 +04:00
alice ##> " /ac cath "
alice <## " cath (Catherine): accepting contact request... "
concurrently_
( cath <## " alice (Alice): contact is connected " )
( alice <## " cath (Catherine): contact is connected " )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @cath " , " " ) , ( " @bob " , " hey " ) ]
2022-02-13 13:19:24 +04:00
alice <##> cath
testDeduplicateContactRequestsProfileChange :: IO ()
testDeduplicateContactRequestsProfileChange = testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
alice ##> " /ad "
cLink <- getContactLink alice True
bob ##> ( " /c " <> cLink )
alice <#? bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@bob " , " " ) ]
2022-02-13 13:19:24 +04:00
bob ##> " /p bob "
bob <## " user full name removed (your contacts are notified) "
bob ##> ( " /c " <> cLink )
bob <## " connection request sent! "
alice <## " bob wants to connect to you! "
alice <## " to accept: /ac bob "
alice <## " to reject: /rc bob (the sender will NOT be notified) "
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@bob " , " " ) ]
2022-02-13 13:19:24 +04:00
bob ##> " /p bob Bob Ross "
bob <## " user full name changed to Bob Ross (your contacts are notified) "
bob ##> ( " /c " <> cLink )
alice <#? bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@bob " , " " ) ]
2022-02-13 13:19:24 +04:00
bob ##> " /p robert Robert "
bob <## " user profile is changed to robert (Robert) (your contacts are notified) "
bob ##> ( " /c " <> cLink )
alice <#? bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@robert " , " " ) ]
2022-02-13 13:19:24 +04:00
alice ##> " /ac bob "
alice <## " no contact request from bob "
alice ##> " /ac robert "
alice <## " robert (Robert): accepting contact request... "
concurrently_
( bob <## " alice (Alice): contact is connected " )
( alice <## " robert (Robert): contact is connected " )
bob ##> ( " /c " <> cLink )
bob <## " alice (Alice): contact already exists "
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @robert " , " " ) ]
2022-04-24 09:05:54 +01:00
bob @@@ [ ( " @alice " , " " ) , ( " :3 " , " " ) , ( " :2 " , " " ) , ( " :1 " , " " ) ]
bob ##> " /_delete :1 "
bob <## " connection :1 deleted "
bob ##> " /_delete :2 "
bob <## " connection :2 deleted "
bob ##> " /_delete :3 "
bob <## " connection :3 deleted "
2022-02-13 13:19:24 +04:00
alice <##> bob
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @robert " , " hey " ) ]
bob @@@ [ ( " @alice " , " hey " ) ]
2022-02-13 13:19:24 +04:00
bob ##> ( " /c " <> cLink )
bob <## " alice (Alice): contact already exists "
alice <##> bob
alice #$> ( " /_get chat @2 count=100 " , chat , [ ( 1 , " hi " ) , ( 0 , " hey " ) , ( 1 , " hi " ) , ( 0 , " hey " ) ] )
bob #$> ( " /_get chat @2 count=100 " , chat , [ ( 0 , " hi " ) , ( 1 , " hey " ) , ( 0 , " hi " ) , ( 1 , " hey " ) ] )
cath ##> ( " /c " <> cLink )
alice <#? cath
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " <@cath " , " " ) , ( " @robert " , " hey " ) ]
2022-02-13 13:19:24 +04:00
alice ##> " /ac cath "
alice <## " cath (Catherine): accepting contact request... "
concurrently_
( cath <## " alice (Alice): contact is connected " )
( alice <## " cath (Catherine): contact is connected " )
2022-04-23 18:23:29 +01:00
alice @@@ [ ( " @cath " , " " ) , ( " @robert " , " hey " ) ]
2022-02-13 13:19:24 +04:00
alice <##> cath
2021-12-08 13:09:51 +00:00
testRejectContactAndDeleteUserContact :: IO ()
testRejectContactAndDeleteUserContact = testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
alice ##> " /ad "
cLink <- getContactLink alice True
bob ##> ( " /c " <> cLink )
alice <#? bob
alice ##> " /rc bob "
alice <## " bob: contact request rejected "
( bob </ )
alice ##> " /sa "
cLink' <- getContactLink alice False
cLink' ` shouldBe ` cLink
alice ##> " /da "
alice <## " Your chat address is deleted - accepted contacts will remain connected. "
alice <## " To create a new chat address use /ad "
cath ##> ( " /c " <> cLink )
2022-04-21 11:50:24 +04:00
cath <## " error: connection authorization failed - this could happen if connection was deleted, secured with different credentials, or due to a bug - please re-create the connection "
2021-12-08 13:09:51 +00:00
testDeleteConnectionRequests :: IO ()
testDeleteConnectionRequests = testChat3 aliceProfile bobProfile cathProfile $
\ alice bob cath -> do
alice ##> " /ad "
cLink <- getContactLink alice True
bob ##> ( " /c " <> cLink )
alice <#? bob
cath ##> ( " /c " <> cLink )
alice <#? cath
alice ##> " /da "
alice <## " Your chat address is deleted - accepted contacts will remain connected. "
alice <## " To create a new chat address use /ad "
alice ##> " /ad "
cLink' <- getContactLink alice True
bob ##> ( " /c " <> cLink' )
-- same names are used here, as they were released at /da
alice <#? bob
cath ##> ( " /c " <> cLink' )
alice <#? cath
2022-03-13 19:34:03 +00:00
testGetSetSMPServers :: IO ()
testGetSetSMPServers =
testChat2 aliceProfile bobProfile $
\ alice _ -> do
alice #$> ( " /smp_servers " , id , " no custom SMP servers saved " )
alice #$> ( " /smp_servers smp://1234-w==@smp1.example.im " , id , " ok " )
alice #$> ( " /smp_servers " , id , " smp://1234-w==@smp1.example.im " )
alice #$> ( " /smp_servers smp://2345-w==@smp2.example.im,smp://3456-w==@smp3.example.im:5224 " , id , " ok " )
alice #$> ( " /smp_servers " , id , " smp://2345-w==@smp2.example.im, smp://3456-w==@smp3.example.im:5224 " )
alice #$> ( " /smp_servers default " , id , " ok " )
alice #$> ( " /smp_servers " , id , " no custom SMP servers saved " )
2022-04-25 16:30:21 +01:00
testAsyncInitiatingOffline :: IO ()
testAsyncInitiatingOffline = withTmpFiles $ do
2022-04-26 12:52:41 +04:00
inv <- withNewTestChat " alice " aliceProfile $ \ alice -> do
2022-04-25 16:30:21 +01:00
alice ##> " /c "
getInvitation alice
2022-04-26 12:52:41 +04:00
withNewTestChat " bob " bobProfile $ \ bob -> do
2022-04-25 16:30:21 +01:00
bob ##> ( " /c " <> inv )
bob <## " confirmation sent! "
2022-04-26 12:52:41 +04:00
withTestChat " alice " $ \ alice -> do
2022-04-25 16:30:21 +01:00
concurrently_
( bob <## " alice (Alice): contact is connected " )
( alice <## " bob (Bob): contact is connected " )
testAsyncAcceptingOffline :: IO ()
testAsyncAcceptingOffline = withTmpFiles $ do
2022-04-26 12:52:41 +04:00
inv <- withNewTestChat " alice " aliceProfile $ \ alice -> do
2022-04-25 16:30:21 +01:00
alice ##> " /c "
getInvitation alice
2022-04-26 12:52:41 +04:00
withNewTestChat " bob " bobProfile $ \ bob -> do
2022-04-25 16:30:21 +01:00
bob ##> ( " /c " <> inv )
bob <## " confirmation sent! "
2022-04-26 12:52:41 +04:00
withTestChat " alice " $ \ alice ->
withTestChat " bob " $ \ bob ->
2022-04-25 16:30:21 +01:00
concurrently_
( bob <## " alice (Alice): contact is connected " )
( alice <## " bob (Bob): contact is connected " )
2022-04-26 12:52:41 +04:00
testFullAsync :: IO ()
testFullAsync = withTmpFiles $ do
inv <- withNewTestChat " alice " aliceProfile $ \ alice -> do
2022-04-25 16:30:21 +01:00
alice ##> " /c "
getInvitation alice
2022-04-26 12:52:41 +04:00
withNewTestChat " bob " bobProfile $ \ bob -> do
2022-04-25 16:30:21 +01:00
bob ##> ( " /c " <> inv )
bob <## " confirmation sent! "
2022-04-26 12:52:41 +04:00
withTestChat " alice " $ \ _ -> pure ()
withTestChat " bob " $ \ _ -> pure ()
withTestChat " alice " $ \ alice ->
2022-04-25 16:30:21 +01:00
alice <## " 1 contacts connected (use /cs for the list) "
2022-04-26 12:52:41 +04:00
withTestChat " bob " $ \ _ -> pure ()
withTestChat " alice " $ \ alice -> do
2022-04-25 16:30:21 +01:00
alice <## " 1 contacts connected (use /cs for the list) "
alice <## " bob (Bob): contact is connected "
2022-04-26 12:52:41 +04:00
withTestChat " bob " $ \ bob -> do
2022-04-25 16:30:21 +01:00
bob <## " 1 contacts connected (use /cs for the list) "
bob <## " alice (Alice): contact is connected "
2022-04-26 12:52:41 +04:00
testAsyncFileTransfer :: IO ()
testAsyncFileTransfer = withTmpFiles $ do
withNewTestChat " alice " aliceProfile $ \ alice ->
withNewTestChat " bob " bobProfile $ \ bob ->
connectUsers alice bob
withTestChatContactConnected " alice " $ \ alice -> do
alice ##> " /_send @2 file ./tests/fixtures/test.jpg text hi, sending a file "
alice <# " @bob hi, sending a file "
alice <# " /f @bob ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
withTestChatContactConnected " bob " $ \ bob -> do
bob <# " alice> hi, sending a file "
bob <# " alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 ./tests/tmp "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
withTestChatContactConnected' " alice "
withTestChatContactConnected' " bob "
withTestChatContactConnected' " alice "
withTestChatContactConnected' " bob "
withTestChatContactConnected " alice " $ \ alice -> do
alice <## " started sending file 1 (test.jpg) to bob "
alice <## " completed sending file 1 (test.jpg) to bob "
withTestChatContactConnected " bob " $ \ bob -> do
bob <## " started receiving file 1 (test.jpg) from alice "
bob <## " completed receiving file 1 (test.jpg) from alice "
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
testAsyncGroupFileTransfer :: IO ()
testAsyncGroupFileTransfer = withTmpFiles $ do
withNewTestChat " alice " aliceProfile $ \ alice ->
withNewTestChat " bob " bobProfile $ \ bob ->
withNewTestChat " cath " cathProfile $ \ cath ->
createGroup3 " team " alice bob cath
withTestChatGroup3Connected " alice " $ \ alice -> do
alice ##> " /_send #1 file ./tests/fixtures/test.jpg json { \ " text \ " : \ " \ " , \ " type \ " : \ " text \ " } "
alice <# " /f #team ./tests/fixtures/test.jpg "
alice <## " use /fc 1 to cancel sending "
withTestChatGroup3Connected " bob " $ \ bob -> do
bob <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 ./tests/tmp/ "
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
withTestChatGroup3Connected " cath " $ \ cath -> do
cath <# " #team alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
cath <## " use /fr 1 [<dir>/ | <path>] to receive it "
cath ##> " /fr 1 ./tests/tmp/ "
cath <## " saving file 1 from alice to ./tests/tmp/test_1.jpg "
withTestChatGroup3Connected' " alice "
withTestChatGroup3Connected' " bob "
withTestChatGroup3Connected' " cath "
withTestChatGroup3Connected' " alice "
withTestChatGroup3Connected' " bob "
withTestChatGroup3Connected' " cath "
withTestChatGroup3Connected' " alice "
withTestChatGroup3Connected " bob " $ \ bob -> do
bob <## " started receiving file 1 (test.jpg) from alice "
withTestChatGroup3Connected " cath " $ \ cath -> do
cath <## " started receiving file 1 (test.jpg) from alice "
withTestChatGroup3Connected " alice " $ \ alice -> do
alice
<### [ " started sending file 1 (test.jpg) to bob " ,
" completed sending file 1 (test.jpg) to bob " ,
" started sending file 1 (test.jpg) to cath " ,
" completed sending file 1 (test.jpg) to cath "
]
withTestChatGroup3Connected " bob " $ \ bob -> do
bob <## " completed receiving file 1 (test.jpg) from alice "
withTestChatGroup3Connected " cath " $ \ cath -> do
cath <## " completed receiving file 1 (test.jpg) from alice "
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
dest ` shouldBe ` src
dest2 <- B . readFile " ./tests/tmp/test_1.jpg "
dest2 ` shouldBe ` src
withTestChatContactConnected :: String -> ( TestCC -> IO a ) -> IO a
withTestChatContactConnected dbPrefix action =
withTestChat dbPrefix $ \ cc -> do
cc <## " 1 contacts connected (use /cs for the list) "
action cc
withTestChatContactConnected' :: String -> IO ()
withTestChatContactConnected' dbPrefix = withTestChatContactConnected dbPrefix $ \ _ -> pure ()
withTestChatGroup3Connected :: String -> ( TestCC -> IO a ) -> IO a
withTestChatGroup3Connected dbPrefix action = do
withTestChat dbPrefix $ \ cc -> do
cc <## " 2 contacts connected (use /cs for the list) "
cc <## " #team: connected to server(s) "
action cc
withTestChatGroup3Connected' :: String -> IO ()
withTestChatGroup3Connected' dbPrefix = withTestChatGroup3Connected dbPrefix $ \ _ -> pure ()
2021-09-04 07:32:56 +01:00
startFileTransfer :: TestCC -> TestCC -> IO ()
startFileTransfer alice bob = do
2021-09-05 14:08:29 +01:00
alice #> " /f @bob ./tests/fixtures/test.jpg "
2021-09-04 07:32:56 +01:00
alice <## " use /fc 1 to cancel sending "
2021-09-05 14:08:29 +01:00
bob <# " alice> sends file test.jpg (136.5 KiB / 139737 bytes) "
2021-09-04 07:32:56 +01:00
bob <## " use /fr 1 [<dir>/ | <path>] to receive it "
bob ##> " /fr 1 ./tests/tmp "
2022-04-05 10:01:08 +04:00
bob <## " saving file 1 from alice to ./tests/tmp/test.jpg "
concurrently_
( bob <## " started receiving file 1 (test.jpg) from alice " )
( alice <## " started sending file 1 (test.jpg) to bob " )
2021-09-04 07:32:56 +01:00
checkPartialTransfer :: IO ()
checkPartialTransfer = do
src <- B . readFile " ./tests/fixtures/test.jpg "
dest <- B . readFile " ./tests/tmp/test.jpg "
B . unpack src ` shouldStartWith ` B . unpack dest
B . length src > B . length dest ` shouldBe ` True
2022-04-15 13:16:34 +01:00
checkActionDeletesFile :: FilePath -> IO () -> IO ()
checkActionDeletesFile file action = do
fileExistsBefore <- doesFileExist file
fileExistsBefore ` shouldBe ` True
action
fileExistsAfter <- doesFileExist file
fileExistsAfter ` shouldBe ` False
waitFileExists :: FilePath -> IO ()
waitFileExists f = unlessM ( doesFileExist f ) $ waitFileExists f
2021-07-16 07:40:55 +01:00
connectUsers :: TestCC -> TestCC -> IO ()
connectUsers cc1 cc2 = do
2021-08-22 15:56:36 +01:00
name1 <- showName cc1
name2 <- showName cc2
2021-08-02 20:10:24 +01:00
cc1 ##> " /c "
2021-08-05 20:51:48 +01:00
inv <- getInvitation cc1
2021-07-16 07:40:55 +01:00
cc2 ##> ( " /c " <> inv )
2021-12-11 12:57:12 +00:00
cc2 <## " confirmation sent! "
2021-07-16 07:40:55 +01:00
concurrently_
2021-08-22 15:56:36 +01:00
( cc2 <## ( name1 <> " : contact is connected " ) )
( cc1 <## ( name2 <> " : contact is connected " ) )
2021-08-02 20:10:24 +01:00
2021-08-22 15:56:36 +01:00
showName :: TestCC -> IO String
showName ( TestCC ChatController { currentUser } _ _ _ _ ) = do
2022-02-06 16:18:01 +00:00
Just User { localDisplayName , profile = Profile { fullName } } <- readTVarIO currentUser
2021-08-22 15:56:36 +01:00
pure . T . unpack $ localDisplayName <> " ( " <> fullName <> " ) "
2021-08-02 20:10:24 +01:00
2022-01-06 13:09:03 +04:00
createGroup2 :: String -> TestCC -> TestCC -> IO ()
createGroup2 gName cc1 cc2 = do
2021-08-02 20:10:24 +01:00
connectUsers cc1 cc2
2021-08-22 15:56:36 +01:00
name2 <- userName cc2
2021-08-05 20:51:48 +01:00
cc1 ##> ( " /g " <> gName )
cc1 <## ( " group # " <> gName <> " is created " )
2021-08-02 20:10:24 +01:00
cc1 <## ( " use /a " <> gName <> " <name> to add members " )
2022-01-06 13:09:03 +04:00
addMember gName cc1 cc2
2021-08-02 20:10:24 +01:00
cc2 ##> ( " /j " <> gName )
concurrently_
2021-08-22 15:56:36 +01:00
( cc1 <## ( " # " <> gName <> " : " <> name2 <> " joined the group " ) )
2021-08-02 20:10:24 +01:00
( cc2 <## ( " # " <> gName <> " : you joined the group " ) )
2022-01-06 13:09:03 +04:00
createGroup3 :: String -> TestCC -> TestCC -> TestCC -> IO ()
createGroup3 gName cc1 cc2 cc3 = do
createGroup2 gName cc1 cc2
connectUsers cc1 cc3
name3 <- userName cc3
sName2 <- showName cc2
sName3 <- showName cc3
addMember gName cc1 cc3
2021-08-02 20:10:24 +01:00
cc3 ##> ( " /j " <> gName )
concurrentlyN_
2021-08-22 15:56:36 +01:00
[ cc1 <## ( " # " <> gName <> " : " <> name3 <> " joined the group " ) ,
2021-08-02 20:10:24 +01:00
do
cc3 <## ( " # " <> gName <> " : you joined the group " )
2021-08-22 15:56:36 +01:00
cc3 <## ( " # " <> gName <> " : member " <> sName2 <> " is connected " ) ,
2021-08-02 20:10:24 +01:00
do
2021-08-22 15:56:36 +01:00
cc2 <## ( " # " <> gName <> " : alice added " <> sName3 <> " to the group (connecting...) " )
cc2 <## ( " # " <> gName <> " : new member " <> name3 <> " is connected " )
2021-08-02 20:10:24 +01:00
]
2022-01-06 13:09:03 +04:00
addMember :: String -> TestCC -> TestCC -> IO ()
addMember gName inviting invitee = do
name1 <- userName inviting
memName <- userName invitee
inviting ##> ( " /a " <> gName <> " " <> memName )
concurrentlyN_
[ inviting <## ( " invitation to join the group # " <> gName <> " sent to " <> memName ) ,
do
invitee <## ( " # " <> gName <> " : " <> name1 <> " invites you to join the group as admin " )
invitee <## ( " use /j " <> gName <> " to accept " )
]
2021-08-02 20:10:24 +01:00
-- | test sending direct messages
( <##> ) :: TestCC -> TestCC -> IO ()
cc1 <##> cc2 = do
2021-08-22 15:56:36 +01:00
name1 <- userName cc1
name2 <- userName cc2
cc1 #> ( " @ " <> name2 <> " hi " )
cc2 <# ( name1 <> " > hi " )
cc2 #> ( " @ " <> name1 <> " hey " )
cc1 <# ( name2 <> " > hey " )
2021-07-07 22:46:38 +01:00
( ##> ) :: TestCC -> String -> IO ()
2021-08-02 20:10:24 +01:00
cc ##> cmd = do
2021-08-05 20:51:48 +01:00
cc ` send ` cmd
2021-07-07 22:46:38 +01:00
cc <## cmd
( #> ) :: TestCC -> String -> IO ()
2021-08-02 20:10:24 +01:00
cc #> cmd = do
2021-08-05 20:51:48 +01:00
cc ` send ` cmd
2021-07-07 22:46:38 +01:00
cc <# cmd
2022-02-09 20:58:02 +04:00
( #$> ) :: ( Eq a , Show a ) => TestCC -> ( String , String -> a , a ) -> Expectation
cc #$> ( cmd , f , res ) = do
cc ##> cmd
( f <$> getTermLine cc ) ` shouldReturn ` res
chat :: String -> [ ( Int , String ) ]
2022-04-10 13:30:58 +04:00
chat = map ( \ ( a , _ , _ ) -> a ) . chat''
2022-03-16 13:20:47 +00:00
chat' :: String -> [ ( ( Int , String ) , Maybe ( Int , String ) ) ]
2022-04-10 13:30:58 +04:00
chat' = map ( \ ( a , b , _ ) -> ( a , b ) ) . chat''
chatF :: String -> [ ( ( Int , String ) , Maybe String ) ]
chatF = map ( \ ( a , _ , c ) -> ( a , c ) ) . chat''
chat'' :: String -> [ ( ( Int , String ) , Maybe ( Int , String ) , Maybe String ) ]
chat'' = read
2022-02-09 20:58:02 +04:00
2022-04-23 18:23:29 +01:00
( @@@ ) :: TestCC -> [ ( String , String ) ] -> Expectation
2022-04-24 09:05:54 +01:00
( @@@ ) = getChats . map $ \ ( ldn , msg , _ ) -> ( ldn , msg )
( @@@! ) :: TestCC -> [ ( String , String , Maybe ConnStatus ) ] -> Expectation
( @@@! ) = getChats id
getChats :: ( Eq a , Show a ) => ( [ ( String , String , Maybe ConnStatus ) ] -> [ a ] ) -> TestCC -> [ a ] -> Expectation
getChats f cc res = do
cc ##> " /_get chats pcc=on "
2022-02-09 20:58:02 +04:00
line <- getTermLine cc
2022-04-24 09:05:54 +01:00
f ( read line ) ` shouldMatchList ` res
2022-02-09 20:58:02 +04:00
2021-08-05 20:51:48 +01:00
send :: TestCC -> String -> IO ()
2022-01-24 16:07:17 +00:00
send TestCC { chatController = cc } cmd = atomically $ writeTBQueue ( inputQ cc ) cmd
2021-07-07 22:46:38 +01:00
( <## ) :: TestCC -> String -> Expectation
2021-08-05 20:51:48 +01:00
cc <## line = getTermLine cc ` shouldReturn ` line
2021-07-07 22:46:38 +01:00
2022-05-01 14:07:18 +01:00
getInAnyOrder :: ( String -> String ) -> TestCC -> [ String ] -> Expectation
getInAnyOrder _ _ [] = pure ()
getInAnyOrder f cc ls = do
line <- f <$> getTermLine cc
2021-07-24 10:26:28 +01:00
if line ` elem ` ls
2022-05-01 14:07:18 +01:00
then getInAnyOrder f cc $ filter ( /= line ) ls
2021-07-24 10:26:28 +01:00
else error $ " unexpected output: " <> line
2022-05-01 14:07:18 +01:00
( <### ) :: TestCC -> [ String ] -> Expectation
( <### ) = getInAnyOrder id
( <##? ) :: TestCC -> [ String ] -> Expectation
( <##? ) = getInAnyOrder dropTime
2021-07-07 22:46:38 +01:00
( <# ) :: TestCC -> String -> Expectation
2021-08-05 20:51:48 +01:00
cc <# line = ( dropTime <$> getTermLine cc ) ` shouldReturn ` line
2021-08-02 20:10:24 +01:00
( </ ) :: TestCC -> Expectation
2022-02-02 23:50:43 +04:00
( </ ) = ( <// 500000 )
2021-07-07 22:46:38 +01:00
2021-12-08 13:09:51 +00:00
( <#? ) :: TestCC -> TestCC -> Expectation
cc1 <#? cc2 = do
name <- userName cc2
sName <- showName cc2
2021-12-11 12:57:12 +00:00
cc2 <## " connection request sent! "
2021-12-08 13:09:51 +00:00
cc1 <## ( sName <> " wants to connect to you! " )
cc1 <## ( " to accept: /ac " <> name )
cc1 <## ( " to reject: /rc " <> name <> " (the sender will NOT be notified) " )
2021-07-07 22:46:38 +01:00
dropTime :: String -> String
dropTime msg = case splitAt 6 msg of
( [ m , m' , ':' , s , s' , ' ' ] , text ) ->
if all isDigit [ m , m' , s , s' ] then text else error " invalid time "
_ -> error " invalid time "
2021-08-05 20:51:48 +01:00
getInvitation :: TestCC -> IO String
getInvitation cc = do
2021-12-08 13:09:51 +00:00
cc <## " pass this invitation link to your contact (via another channel): "
2021-08-05 20:51:48 +01:00
cc <## " "
inv <- getTermLine cc
cc <## " "
2021-12-08 13:09:51 +00:00
cc <## " and ask them to connect: /c <invitation_link_above> "
2021-08-05 20:51:48 +01:00
pure inv
2021-12-08 13:09:51 +00:00
getContactLink :: TestCC -> Bool -> IO String
getContactLink cc created = do
cc <## if created then " Your new chat address is created! " else " Your chat address: "
cc <## " "
link <- getTermLine cc
cc <## " "
cc <## " Anybody can send you contact requests with: /c <contact_link_above> "
cc <## " to show it again: /sa "
cc <## " to delete it: /da (accepted contacts will remain connected) "
pure link