1 // OpenTween - Client of Twitter
2 // Copyright (c) 2014 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
23 using System.Collections.Generic;
25 using System.Reflection;
28 using Xunit.Extensions;
30 namespace OpenTween.Models
32 public class TabInformationTest
34 private TabInformations tabinfo;
36 public TabInformationTest()
38 this.tabinfo = Activator.CreateInstance(typeof(TabInformations), true) as TabInformations;
40 // TabInformation.GetInstance() で取得できるようにする
41 var field = typeof(TabInformations).GetField("_instance",
42 BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.SetField);
43 field.SetValue(null, this.tabinfo);
46 this.tabinfo.AddTab(new HomeTabModel("Recent"));
47 this.tabinfo.AddTab(new MentionsTabModel("Reply"));
48 this.tabinfo.AddTab(new DirectMessagesTabModel("DM"));
49 this.tabinfo.AddTab(new FavoritesTabModel("Favorites"));
53 public void AddTab_Test()
55 var tab = new FilterTabModel("MyTab");
56 var ret = this.tabinfo.AddTab(tab);
59 Assert.Same(tab, this.tabinfo.Tabs.Values.Last());
63 public void AddTab_DuplicateTest()
65 var ret = this.tabinfo.AddTab(new FilterTabModel("Recent"));
71 public void SelectTab_Test()
73 this.tabinfo.SelectTab("Reply");
75 Assert.Equal("Reply", this.tabinfo.SelectedTabName);
76 Assert.IsType<MentionsTabModel>(this.tabinfo.SelectedTab);
80 public void SelectTab_NotExistTest()
81 => Assert.Throws<ArgumentException>(() => this.tabinfo.SelectTab("INVALID"));
84 public void MakeTabName_Test()
86 var baseTabName = "NewTab";
87 Assert.Equal("NewTab", this.tabinfo.MakeTabName(baseTabName, 5));
91 public void MakeTabName_RetryTest()
93 this.tabinfo.AddTab(new FilterTabModel("NewTab"));
94 this.tabinfo.AddTab(new FilterTabModel("NewTab2"));
96 var baseTabName = "NewTab";
97 Assert.Equal("NewTab3", this.tabinfo.MakeTabName(baseTabName, 5));
101 public void MakeTabName_RetryErrorTest()
103 this.tabinfo.AddTab(new FilterTabModel("NewTab"));
104 this.tabinfo.AddTab(new FilterTabModel("NewTab2"));
105 this.tabinfo.AddTab(new FilterTabModel("NewTab3"));
106 this.tabinfo.AddTab(new FilterTabModel("NewTab4"));
107 this.tabinfo.AddTab(new FilterTabModel("NewTab5"));
109 var baseTabName = "NewTab";
110 Assert.Throws<TabException>(() => this.tabinfo.MakeTabName(baseTabName, 5));
114 public void IsMuted_Test()
116 this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
118 var post = new PostClass
123 Assert.True(this.tabinfo.IsMuted(post, isHomeTimeline: true));
127 public void IsMuted_NotMutingTest()
129 this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
131 var post = new PostClass
136 Assert.False(this.tabinfo.IsMuted(post, isHomeTimeline: true));
140 public void IsMuted_RetweetTest()
142 this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
144 var post = new PostClass
147 RetweetedByUserId = 12345L,
150 Assert.True(this.tabinfo.IsMuted(post, isHomeTimeline: true));
154 public void IsMuted_RetweetNotMutingTest()
156 this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
158 var post = new PostClass
161 RetweetedByUserId = 22222L,
164 Assert.False(this.tabinfo.IsMuted(post, isHomeTimeline: true));
168 public void IsMuted_ReplyTest()
170 this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
172 // ミュート対象のユーザーであってもリプライの場合は対象外とする
173 var post = new PostClass
176 Text = "@foo hogehoge",
179 Assert.False(this.tabinfo.IsMuted(post, isHomeTimeline: true));
183 public void IsMuted_NotInHomeTimelineTest()
185 this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
187 // Recent以外のタブ(検索など)の場合は対象外とする
188 var post = new PostClass
193 Assert.False(this.tabinfo.IsMuted(post, isHomeTimeline: false));
197 public void IsMuted_MuteTabRulesTest()
199 this.tabinfo.MuteUserIds = new HashSet<long> { };
201 var muteTab = new MuteTabModel();
202 muteTab.AddFilter(new PostFilterRule
207 this.tabinfo.AddTab(muteTab);
209 var post = new PostClass
215 Assert.True(this.tabinfo.IsMuted(post, isHomeTimeline: true));
219 public void IsMuted_MuteTabRules_NotInHomeTimelineTest()
221 this.tabinfo.MuteUserIds = new HashSet<long> { };
223 var muteTab = new MuteTabModel();
224 muteTab.AddFilter(new PostFilterRule
229 this.tabinfo.AddTab(muteTab);
231 // ミュートタブによるミュートはリプライも対象とする
232 var post = new PostClass
236 Text = "@hoge hogehoge",
239 Assert.True(this.tabinfo.IsMuted(post, isHomeTimeline: false));
243 public void SetReadAllTab_MarkAsReadTest()
245 var tab1 = new PublicSearchTabModel("search1");
246 var tab2 = new PublicSearchTabModel("search2");
248 this.tabinfo.AddTab(tab1);
249 this.tabinfo.AddTab(tab2);
251 // search1 に追加するツイート (StatusId: 100, 150, 200; すべて未読)
252 tab1.UnreadManage = true;
253 tab1.AddPostQueue(new PostClass { StatusId = 100L, IsRead = false });
254 tab1.AddPostQueue(new PostClass { StatusId = 150L, IsRead = false });
255 tab1.AddPostQueue(new PostClass { StatusId = 200L, IsRead = false });
257 // search2 に追加するツイート (StatusId: 150, 200, 250; すべて未読)
258 tab2.UnreadManage = true;
259 tab2.AddPostQueue(new PostClass { StatusId = 150L, IsRead = false });
260 tab2.AddPostQueue(new PostClass { StatusId = 200L, IsRead = false });
261 tab2.AddPostQueue(new PostClass { StatusId = 250L, IsRead = false });
263 this.tabinfo.DistributePosts();
264 this.tabinfo.SubmitUpdate();
267 Assert.Equal(3, tab1.UnreadCount);
268 Assert.Equal(3, tab2.UnreadCount);
272 // StatusId: 200 を既読にする (search1, search2 両方に含まれる)
273 this.tabinfo.SetReadAllTab(200L, read: true);
274 Assert.Equal(2, tab1.UnreadCount);
275 Assert.Equal(2, tab2.UnreadCount);
277 // StatusId: 100 を既読にする (search1 のみに含まれる)
278 this.tabinfo.SetReadAllTab(100L, read: true);
279 Assert.Equal(1, tab1.UnreadCount);
280 Assert.Equal(2, tab2.UnreadCount);
284 public void SetReadAllTab_MarkAsUnreadTest()
286 var tab1 = new PublicSearchTabModel("search1");
287 var tab2 = new PublicSearchTabModel("search2");
289 this.tabinfo.AddTab(tab1);
290 this.tabinfo.AddTab(tab2);
292 // search1 に追加するツイート (StatusId: 100, 150, 200; すべて既読)
293 tab1.UnreadManage = true;
294 tab1.AddPostQueue(new PostClass { StatusId = 100L, IsRead = true });
295 tab1.AddPostQueue(new PostClass { StatusId = 150L, IsRead = true });
296 tab1.AddPostQueue(new PostClass { StatusId = 200L, IsRead = true });
298 // search2 に追加するツイート (StatusId: 150, 200, 250; すべて既読)
299 tab2.UnreadManage = true;
300 tab2.AddPostQueue(new PostClass { StatusId = 150L, IsRead = true });
301 tab2.AddPostQueue(new PostClass { StatusId = 200L, IsRead = true });
302 tab2.AddPostQueue(new PostClass { StatusId = 250L, IsRead = true });
304 this.tabinfo.DistributePosts();
305 this.tabinfo.SubmitUpdate();
308 Assert.Equal(0, tab1.UnreadCount);
309 Assert.Equal(0, tab2.UnreadCount);
313 // StatusId: 200 を未読にする (search1, search2 両方に含まれる)
314 this.tabinfo.SetReadAllTab(200L, read: false);
315 Assert.Equal(1, tab1.UnreadCount);
316 Assert.Equal(1, tab2.UnreadCount);
318 // StatusId: 100 を未読にする (search1 のみに含まれる)
319 this.tabinfo.SetReadAllTab(100L, read: false);
320 Assert.Equal(2, tab1.UnreadCount);
321 Assert.Equal(1, tab2.UnreadCount);
325 public void SetReadHomeTab_Test()
327 var homeTab = this.tabinfo.Tabs["Recent"];
329 // Recent に追加するツイート (StatusId: 100, 150, 200; すべて未読)
330 homeTab.UnreadManage = true;
331 this.tabinfo.AddPost(new PostClass { StatusId = 100L, IsRead = false });
332 this.tabinfo.AddPost(new PostClass { StatusId = 150L, IsRead = false });
333 this.tabinfo.AddPost(new PostClass { StatusId = 200L, IsRead = false });
335 this.tabinfo.DistributePosts();
336 this.tabinfo.SubmitUpdate();
339 Assert.Equal(3, homeTab.UnreadCount);
341 // Recent タブのツイートをすべて未読にする
342 this.tabinfo.SetReadHomeTab();
343 Assert.Equal(0, homeTab.UnreadCount);
347 public void SetReadHomeTab_ContainsReplyTest()
349 var homeTab = this.tabinfo.Tabs["Recent"];
351 // Recent に追加するツイート (StatusId: 100, 150, 200; すべて未読)
352 // StatusId: 150 は未読だがリプライ属性が付いている
353 homeTab.UnreadManage = true;
354 this.tabinfo.AddPost(new PostClass { StatusId = 100L, IsRead = false });
355 this.tabinfo.AddPost(new PostClass { StatusId = 150L, IsRead = false, IsReply = true });
356 this.tabinfo.AddPost(new PostClass { StatusId = 200L, IsRead = false });
358 this.tabinfo.DistributePosts();
359 this.tabinfo.SubmitUpdate();
362 Assert.Equal(3, homeTab.UnreadCount);
364 // Recent タブのツイートをすべて未読にする
365 this.tabinfo.SetReadHomeTab();
367 // リプライである StatusId: 150 を除いてすべて未読になっている
368 Assert.Equal(1, homeTab.UnreadCount);
369 Assert.Equal(150L, homeTab.NextUnreadId);
373 public void SetReadHomeTab_ContainsFilterHitTest()
375 var homeTab = this.tabinfo.Tabs["Recent"];
377 // Recent に追加するツイート (StatusId: 100, 150, 200; すべて未読)
378 homeTab.UnreadManage = true;
379 this.tabinfo.AddPost(new PostClass { StatusId = 100L, IsRead = false });
380 this.tabinfo.AddPost(new PostClass { StatusId = 150L, IsRead = false });
381 this.tabinfo.AddPost(new PostClass { StatusId = 200L, IsRead = false });
383 // StatusId: 150 だけ FilterTab の振り分けルールにヒットする (PostClass.FilterHit が true になる)
384 var filterTab = new FilterTabModel("FilterTab");
385 filterTab.AddFilter(TestPostFilterRule.Create(x =>
386 x.StatusId == 150L ? MyCommon.HITRESULT.Copy : MyCommon.HITRESULT.None));
387 this.tabinfo.AddTab(filterTab);
389 this.tabinfo.DistributePosts();
390 this.tabinfo.SubmitUpdate();
393 Assert.Equal(3, homeTab.UnreadCount);
395 // Recent タブのツイートをすべて未読にする
396 this.tabinfo.SetReadHomeTab();
398 // FilterHit が true である StatusId: 150 を除いてすべて未読になっている
399 Assert.Equal(1, homeTab.UnreadCount);
400 Assert.Equal(150L, homeTab.NextUnreadId);
404 public void SubmitUpdate_RemoveSubmit_Test()
406 var homeTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Home);
408 this.tabinfo.AddPost(new PostClass { StatusId = 100L });
409 this.tabinfo.DistributePosts();
410 this.tabinfo.SubmitUpdate();
412 Assert.Equal(1, homeTab.AllCount);
414 this.tabinfo.RemovePostFromAllTabs(100L, setIsDeleted: true);
417 Assert.Equal(1, homeTab.AllCount);
419 this.tabinfo.SubmitUpdate(out var soundFile, out var notifyPosts,
420 out var newMentionOrDm, out var isDeletePost);
422 Assert.True(isDeletePost);
423 Assert.Equal(0, homeTab.AllCount);
424 Assert.False(this.tabinfo.Posts.ContainsKey(100L));
428 public void SubmitUpdate_RemoveSubmit_NotOrphaned_Test()
430 var homeTab = this.tabinfo.GetTabByType<HomeTabModel>();
431 var favTab = this.tabinfo.GetTabByType<FavoritesTabModel>();
433 this.tabinfo.AddPost(new PostClass { StatusId = 100L, IsFav = true });
434 this.tabinfo.DistributePosts();
435 this.tabinfo.SubmitUpdate();
437 Assert.Equal(1, homeTab.AllCount);
438 Assert.Equal(1, favTab.AllCount);
440 // favTab のみ発言を除去 (homeTab には残ったまま)
441 favTab.EnqueueRemovePost(100L, setIsDeleted: false);
444 Assert.Equal(1, homeTab.AllCount);
445 Assert.Equal(1, favTab.AllCount);
447 this.tabinfo.SubmitUpdate(out var soundFile, out var notifyPosts,
448 out var newMentionOrDm, out var isDeletePost);
450 Assert.True(isDeletePost);
451 Assert.Equal(1, homeTab.AllCount);
452 Assert.Equal(0, favTab.AllCount);
454 // homeTab には発言が残っているので Posts からは削除されない
455 Assert.True(this.tabinfo.Posts.ContainsKey(100L));
459 public void SubmitUpdate_NotifyPriorityTest()
461 var homeTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Home);
462 homeTab.UnreadManage = true;
463 homeTab.SoundFile = "home.wav";
465 var replyTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Mentions);
466 replyTab.UnreadManage = true;
467 replyTab.SoundFile = "reply.wav";
469 var dmTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.DirectMessage);
470 dmTab.UnreadManage = true;
471 dmTab.SoundFile = "dm.wav";
474 this.tabinfo.AddPost(new PostClass { StatusId = 100L, IsRead = false });
477 this.tabinfo.AddPost(new PostClass { StatusId = 200L, IsReply = true, IsRead = false });
480 dmTab.AddPostQueue(new PostClass { StatusId = 300L, IsDm = true, IsRead = false });
482 this.tabinfo.DistributePosts();
484 this.tabinfo.SubmitUpdate(out var soundFile, out var notifyPosts,
485 out var newMentionOrDm, out var isDeletePost);
487 // DM が最も優先度が高いため DM の通知音が再生される
488 Assert.Equal("dm.wav", soundFile);
491 Assert.Equal(3, notifyPosts.Length);
495 public void SubmitUpdate_IgnoreEmptySoundPath_Test()
497 var homeTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Home);
498 homeTab.UnreadManage = true;
499 homeTab.SoundFile = "home.wav";
501 var replyTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Mentions);
502 replyTab.UnreadManage = true;
503 replyTab.SoundFile = "";
506 this.tabinfo.AddPost(new PostClass { StatusId = 100L, IsRead = false });
509 this.tabinfo.AddPost(new PostClass { StatusId = 200L, IsReply = true, IsRead = false });
511 this.tabinfo.DistributePosts();
513 this.tabinfo.SubmitUpdate(out var soundFile, out var notifyPosts,
514 out var newMentionOrDm, out var isDeletePost);
516 // リプライの方が通知音の優先度が高いが、replyTab.SoundFile が空文字列なので次点の Recent の通知音を鳴らす
517 Assert.Equal("home.wav", soundFile);
520 Assert.Equal(2, notifyPosts.Length);
524 public void FilterAll_CopyFilterTest()
526 var homeTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Home);
528 var myTab1 = new FilterTabModel("MyTab1");
529 this.tabinfo.AddTab(myTab1);
531 var filter = new PostFilterRule
539 myTab1.AddFilter(filter);
540 myTab1.FilterModified = false;
542 this.tabinfo.AddPost(new PostClass { StatusId = 100L, ScreenName = "aaa" });
543 this.tabinfo.AddPost(new PostClass { StatusId = 200L, ScreenName = "bbb" });
544 this.tabinfo.AddPost(new PostClass { StatusId = 300L, ScreenName = "ccc" });
545 this.tabinfo.DistributePosts();
546 this.tabinfo.SubmitUpdate();
549 Assert.Equal(new[] { 100L, 200L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
550 Assert.Equal(new[] { 100L }, myTab1.StatusIds);
553 filter.FilterName = "bbb";
556 this.tabinfo.FilterAll();
557 this.tabinfo.DistributePosts();
558 this.tabinfo.SubmitUpdate();
561 // [statusId: 100] は MyTab1 から取り除かれる
562 // [statusId: 200] は Recent から MyTab1 にコピーされる
565 Assert.Equal(new[] { 100L, 200L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
566 Assert.Equal(new[] { 200L }, myTab1.StatusIds);
570 public void FilterAll_CopyAndMarkFilterTest()
572 var homeTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Home);
574 var myTab1 = new FilterTabModel("MyTab1");
575 this.tabinfo.AddTab(myTab1);
577 var filter = new PostFilterRule
585 myTab1.AddFilter(filter);
586 myTab1.FilterModified = false;
588 this.tabinfo.AddPost(new PostClass { StatusId = 100L, ScreenName = "aaa" });
589 this.tabinfo.AddPost(new PostClass { StatusId = 200L, ScreenName = "bbb" });
590 this.tabinfo.AddPost(new PostClass { StatusId = 300L, ScreenName = "ccc" });
591 this.tabinfo.DistributePosts();
592 this.tabinfo.SubmitUpdate();
595 Assert.Equal(new[] { 100L, 200L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
596 Assert.Equal(new[] { 100L }, myTab1.StatusIds);
599 filter.FilterName = "bbb";
602 this.tabinfo.FilterAll();
603 this.tabinfo.DistributePosts();
604 this.tabinfo.SubmitUpdate();
607 // [statusId: 100] は MyTab1 から取り除かれる
608 // [statusId: 200] は Recent から MyTab1 にコピーされ、マークが付与される
611 Assert.Equal(new[] { 100L, 200L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
612 Assert.Equal(new[] { 200L }, myTab1.StatusIds);
614 // [statusId: 200] は IsMark が true の状態になる
615 Assert.True(this.tabinfo[200L].IsMark);
619 public void FilterAll_MoveFilterTest()
621 var homeTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Home);
623 var myTab1 = new FilterTabModel("MyTab1");
624 this.tabinfo.AddTab(myTab1);
626 var filter = new PostFilterRule
633 myTab1.AddFilter(filter);
634 myTab1.FilterModified = false;
636 this.tabinfo.AddPost(new PostClass { StatusId = 100L, ScreenName = "aaa" });
637 this.tabinfo.AddPost(new PostClass { StatusId = 200L, ScreenName = "bbb" });
638 this.tabinfo.AddPost(new PostClass { StatusId = 300L, ScreenName = "ccc" });
639 this.tabinfo.DistributePosts();
640 this.tabinfo.SubmitUpdate();
643 Assert.Equal(new[] { 200L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
644 Assert.Equal(new[] { 100L }, myTab1.StatusIds);
647 filter.FilterName = "bbb";
650 this.tabinfo.FilterAll();
651 this.tabinfo.DistributePosts();
652 this.tabinfo.SubmitUpdate();
655 // [statusId: 100] は MyTab1 から取り除かれて Recent に戻される
656 // [statusId: 200] は Recent から MyTab1 に移動される
659 Assert.Equal(new[] { 100L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
660 Assert.Equal(new[] { 200L }, myTab1.StatusIds);
664 public void FilterAll_MoveFilterTest2()
666 var homeTab = this.tabinfo.GetTabByType(MyCommon.TabUsageType.Home);
668 var myTab1 = new FilterTabModel("MyTab1");
669 var myTab2 = new FilterTabModel("MyTab2");
670 this.tabinfo.AddTab(myTab1);
671 this.tabinfo.AddTab(myTab2);
673 var filter1 = new PostFilterRule
680 myTab1.AddFilter(filter1);
681 myTab1.FilterModified = false;
683 var filter2 = new PostFilterRule
690 myTab2.AddFilter(filter2);
691 myTab2.FilterModified = false;
693 this.tabinfo.AddPost(new PostClass { StatusId = 100L, ScreenName = "aaa" });
694 this.tabinfo.AddPost(new PostClass { StatusId = 200L, ScreenName = "bbb" });
695 this.tabinfo.AddPost(new PostClass { StatusId = 300L, ScreenName = "ccc" });
696 this.tabinfo.DistributePosts();
697 this.tabinfo.SubmitUpdate();
700 Assert.Equal(new[] { 300L }, homeTab.StatusIds);
701 Assert.Equal(new[] { 100L }, myTab1.StatusIds);
702 Assert.Equal(new[] { 200L }, myTab2.StatusIds);
705 filter1.FilterName = "bbb";
708 filter2.FilterName = "ccc";
711 this.tabinfo.FilterAll();
712 this.tabinfo.DistributePosts();
713 this.tabinfo.SubmitUpdate();
716 // [statusId: 100] は MyTab1 から取り除かれて Recent に戻される
717 // [statusId: 200] は MyTab1 に移動される
718 // [statusId: 200] は MyTab2 から取り除かれるが MyTab1 に移動されているので Recent には戻さない
719 // [statusId: 300] は Recent から MyTab2 に移動される
722 Assert.Equal(new[] { 100L }, homeTab.StatusIds);
723 Assert.Equal(new[] { 200L }, myTab1.StatusIds);
724 Assert.Equal(new[] { 300L }, myTab2.StatusIds);
728 public void FilterAll_ExcludeReplyFilterTest()
730 var homeTab = this.tabinfo.GetTabByType<HomeTabModel>();
731 var replyTab = this.tabinfo.GetTabByType<MentionsTabModel>();
733 var filter = new PostFilterRule
735 // @aaa からのリプライは Reply タブに振り分けない
736 ExFilterName = "aaa",
738 replyTab.AddFilter(filter);
739 replyTab.FilterModified = false;
741 this.tabinfo.AddPost(new PostClass { StatusId = 100L, ScreenName = "aaa", IsReply = true });
742 this.tabinfo.AddPost(new PostClass { StatusId = 200L, ScreenName = "bbb", IsReply = true });
743 this.tabinfo.AddPost(new PostClass { StatusId = 300L, ScreenName = "ccc", IsReply = true });
744 this.tabinfo.DistributePosts();
745 this.tabinfo.SubmitUpdate();
748 Assert.Equal(new[] { 100L, 200L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
749 Assert.Equal(new[] { 200L, 300L }, replyTab.StatusIds, AnyOrderComparer<long>.Instance);
751 // [statusId: 100] は IsExcludeReply が true の状態になっている
752 Assert.True(this.tabinfo[100L].IsExcludeReply);
755 filter.ExFilterName = "bbb";
758 this.tabinfo.FilterAll();
759 this.tabinfo.DistributePosts();
760 this.tabinfo.SubmitUpdate();
763 // [statusId: 100] は Reply にコピーされ、IsExcludeReply が false になる
764 // [statusId: 200] は Reply から取り除かれ、IsExcludeReply が true になる
767 Assert.Equal(new[] { 100L, 200L, 300L }, homeTab.StatusIds, AnyOrderComparer<long>.Instance);
768 Assert.Equal(new[] { 100L, 300L }, replyTab.StatusIds, AnyOrderComparer<long>.Instance);
770 // [statusId: 100] は IsExcludeReply が false の状態になる
771 Assert.False(this.tabinfo[100L].IsExcludeReply);
773 // [statusId: 200] は IsExcludeReply が true の状態になる
774 Assert.True(this.tabinfo[200L].IsExcludeReply);
777 class TestPostFilterRule : PostFilterRule
779 public static PostFilterRule Create(Func<PostClass, MyCommon.HITRESULT> filterDelegate)
781 return new TestPostFilterRule
783 FilterDelegate = filterDelegate,