@@ -469,6 +469,175 @@ void main() {
469
469
}
470
470
}
471
471
});
472
+
473
+ group ('moves' , () {
474
+ final origChannel = eg.stream ();
475
+ const origTopic = 'origTopic' ;
476
+ const newTopic = 'newTopic' ;
477
+
478
+ late List <StreamMessage > readMessages;
479
+ late List <StreamMessage > unreadMessages;
480
+
481
+ Future <void > prepareStore () async {
482
+ prepare ();
483
+ await channelStore.addStream (origChannel);
484
+ await channelStore.addSubscription (eg.subscription (origChannel));
485
+ readMessages = List <StreamMessage >.generate (10 ,
486
+ (_) => eg.streamMessage (stream: origChannel, topic: origTopic,
487
+ flags: [MessageFlag .read]));
488
+ unreadMessages = List <StreamMessage >.generate (10 ,
489
+ (_) => eg.streamMessage (stream: origChannel, topic: origTopic));
490
+ }
491
+
492
+ List <StreamMessage > copyMessagesWith (Iterable <StreamMessage > messages, {
493
+ ZulipStream ? newChannel,
494
+ String ? newTopic,
495
+ }) {
496
+ assert (newChannel != null || newTopic != null );
497
+ return messages.map ((message) => StreamMessage .fromJson (
498
+ message.toJson ()
499
+ ..['stream_id' ] = newChannel? .streamId ?? message.streamId
500
+ ..['subject' ] = newTopic ?? message.topic
501
+ )).toList ();
502
+ }
503
+
504
+ test ('moved messages = unread messages' , () async {
505
+ await prepareStore ();
506
+ final newChannel = eg.stream ();
507
+ await channelStore.addStream (newChannel);
508
+ await channelStore.addSubscription (eg.subscription (newChannel));
509
+ fillWithMessages (unreadMessages);
510
+ final originalMessageIds =
511
+ model.streams[origChannel.streamId]! [TopicName (origTopic)]! ;
512
+
513
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
514
+ origMessages: unreadMessages,
515
+ newStreamId: newChannel.streamId,
516
+ newTopicStr: newTopic));
517
+ checkNotifiedOnce ();
518
+ checkMatchesMessages (copyMessagesWith (unreadMessages,
519
+ newChannel: newChannel, newTopic: newTopic));
520
+ final newMessageIds =
521
+ model.streams[newChannel.streamId]! [TopicName (newTopic)]! ;
522
+ // Check we successfully avoided making a copy of the list.
523
+ check (originalMessageIds).identicalTo (newMessageIds);
524
+ });
525
+
526
+ test ('moved messages ⊂ read messages' , () async {
527
+ await prepareStore ();
528
+ final messagesToMove = readMessages.take (2 ).toList ();
529
+ fillWithMessages (unreadMessages + readMessages);
530
+
531
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
532
+ origMessages: messagesToMove,
533
+ newTopicStr: newTopic));
534
+ checkNotNotified ();
535
+ checkMatchesMessages (unreadMessages);
536
+ });
537
+
538
+ test ('moved messages ⊂ unread messages' , () async {
539
+ await prepareStore ();
540
+ final messagesToMove = unreadMessages.take (2 ).toList ();
541
+ fillWithMessages (unreadMessages + readMessages);
542
+
543
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
544
+ origMessages: messagesToMove,
545
+ newTopicStr: newTopic));
546
+ checkNotifiedOnce ();
547
+ checkMatchesMessages ([
548
+ ...copyMessagesWith (messagesToMove, newTopic: newTopic),
549
+ ...unreadMessages.skip (2 ),
550
+ ]);
551
+ });
552
+
553
+ test ('moved messages ∩ unread messages ≠ Ø, moved messages ∩ read messages ≠ Ø, moved messages ⊅ unread messages' , () async {
554
+ await prepareStore ();
555
+ final messagesToMove = [unreadMessages.first, readMessages.first];
556
+ fillWithMessages (unreadMessages + readMessages);
557
+
558
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
559
+ origMessages: messagesToMove,
560
+ newTopicStr: newTopic));
561
+ checkNotifiedOnce ();
562
+ checkMatchesMessages ([
563
+ ...copyMessagesWith (unreadMessages.take (1 ), newTopic: newTopic),
564
+ ...unreadMessages.skip (1 ),
565
+ ]);
566
+ });
567
+
568
+ test ('moved messages ⊃ unread messages' , () async {
569
+ await prepareStore ();
570
+ final messagesToMove = unreadMessages + readMessages.take (2 ).toList ();
571
+ fillWithMessages (unreadMessages + readMessages);
572
+ final originalMessageIds =
573
+ model.streams[origChannel.streamId]! [TopicName (origTopic)]! ;
574
+
575
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
576
+ origMessages: messagesToMove,
577
+ newTopicStr: newTopic));
578
+ checkNotifiedOnce ();
579
+ checkMatchesMessages (copyMessagesWith (unreadMessages, newTopic: newTopic));
580
+ final newMessageIds =
581
+ model.streams[origChannel.streamId]! [TopicName (newTopic)]! ;
582
+ // Check we successfully avoided making a copy of the list.
583
+ check (originalMessageIds).identicalTo (newMessageIds);
584
+ });
585
+
586
+ test ('moving to unsubscribed channels drops the unreads' , () async {
587
+ await prepareStore ();
588
+ final unsubscribedChannel = eg.stream ();
589
+ await channelStore.addStream (unsubscribedChannel);
590
+ assert (! channelStore.subscriptions.containsKey (
591
+ unsubscribedChannel.streamId));
592
+ fillWithMessages (unreadMessages);
593
+
594
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
595
+ origMessages: unreadMessages,
596
+ newStreamId: unsubscribedChannel.streamId));
597
+ checkNotifiedOnce ();
598
+ checkMatchesMessages ([]);
599
+ });
600
+
601
+ test ('tolerates unsorted messages' , () async {
602
+ await prepareStore ();
603
+ final unreadMessages = List .generate (10 , (i) =>
604
+ eg.streamMessage (
605
+ id: 1000 - i, stream: origChannel, topic: origTopic));
606
+ fillWithMessages (unreadMessages);
607
+
608
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
609
+ origMessages: unreadMessages,
610
+ newTopicStr: newTopic));
611
+ checkNotifiedOnce ();
612
+ checkMatchesMessages (copyMessagesWith (unreadMessages, newTopic: newTopic));
613
+ });
614
+
615
+ test ('tolerates unreads unknown to the model' , () async {
616
+ await prepareStore ();
617
+ fillWithMessages (unreadMessages);
618
+
619
+ final unknownChannel = eg.stream ();
620
+ assert (! channelStore.streams.containsKey (unknownChannel.streamId));
621
+ final unknownUnreadMessage = eg.streamMessage (
622
+ stream: unknownChannel, topic: origTopic);
623
+
624
+ model.handleUpdateMessageEvent (eg.updateMessageEventMoveFrom (
625
+ origMessages: [unknownUnreadMessage],
626
+ newTopicStr: newTopic));
627
+ checkNotNotified ();
628
+ checkMatchesMessages (unreadMessages);
629
+ });
630
+
631
+ test ('message edit but no move' , () async {
632
+ await prepareStore ();
633
+ fillWithMessages (unreadMessages);
634
+
635
+ model.handleUpdateMessageEvent (eg.updateMessageEditEvent (
636
+ unreadMessages.first));
637
+ checkNotNotified ();
638
+ checkMatchesMessages (unreadMessages);
639
+ });
640
+ });
472
641
});
473
642
474
643
0 commit comments