OSDN Git Service

GetAccountForTabでアカウントが不明な場合にnullの代わりにInvalidAccountインスタンスを返す
authorKimura Youichi <kim.upsilon@bucyou.net>
Thu, 2 May 2024 16:26:53 +0000 (01:26 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Mon, 20 May 2024 17:06:08 +0000 (02:06 +0900)
OpenTween.Tests/SocialProtocol/AccountCollectionTest.cs
OpenTween.Tests/SocialProtocol/InvalidAccountTest.cs [new file with mode: 0644]
OpenTween/SocialProtocol/AccountCollection.cs
OpenTween/SocialProtocol/InvalidAccount.cs [new file with mode: 0644]
OpenTween/Tween.cs

index ae35efc..28f9a16 100644 (file)
@@ -177,7 +177,8 @@ namespace OpenTween.SocialProtocol
 
             // SourceAccountId が null のタブに対しては Primary のアカウントを返す
             var actual = accounts.GetAccountForTab(tabWithoutAccountId);
-            Assert.Equal(new("00000000-0000-4000-8000-000000000000"), actual?.UniqueKey);
+            Assert.IsType<TwitterAccount>(actual);
+            Assert.Equal(new("00000000-0000-4000-8000-000000000000"), actual.UniqueKey);
         }
 
         [Fact]
@@ -198,7 +199,8 @@ namespace OpenTween.SocialProtocol
 
             // SourceAccountId が設定されているタブに対しては対応するアカウントを返す
             var actual = accounts.GetAccountForTab(tabWithAccountId);
-            Assert.Equal(new("00000000-0000-4000-8000-111111111111"), actual?.UniqueKey);
+            Assert.IsType<TwitterAccount>(actual);
+            Assert.Equal(new("00000000-0000-4000-8000-111111111111"), actual.UniqueKey);
         }
 
         [Fact]
@@ -216,8 +218,10 @@ namespace OpenTween.SocialProtocol
 
             var tabWithAccountId = new RelatedPostsTabModel("hoge", new("00000000-0000-4000-8000-999999999999"), new());
 
-            // SourceAccountId に存在しない ID が設定されていた場合は null を返す
-            Assert.Null(accounts.GetAccountForTab(tabWithAccountId));
+            // SourceAccountId に存在しない ID が設定されていた場合は InvalidAccount を返す
+            var actual = accounts.GetAccountForTab(tabWithAccountId);
+            Assert.IsType<InvalidAccount>(actual);
+            Assert.Equal(new("00000000-0000-4000-8000-999999999999"), actual.UniqueKey);
         }
     }
 }
diff --git a/OpenTween.Tests/SocialProtocol/InvalidAccountTest.cs b/OpenTween.Tests/SocialProtocol/InvalidAccountTest.cs
new file mode 100644 (file)
index 0000000..4b12eff
--- /dev/null
@@ -0,0 +1,52 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2024 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+using System;
+using System.Threading.Tasks;
+using OpenTween.Connection;
+using Xunit;
+
+namespace OpenTween.SocialProtocol
+{
+    public class InvalidAccountTest
+    {
+        [Fact]
+        public async Task Connection_Test()
+        {
+            using var account = new InvalidAccount(Guid.NewGuid());
+            var requeset = new GetRequest { RequestUri = new("https://example.com/aaa") };
+
+            await Assert.ThrowsAsync<WebApiException>(
+                () => account.Connection.SendAsync(requeset)
+            );
+        }
+
+        [Fact]
+        public async Task Client_Test()
+        {
+            using var account = new InvalidAccount(Guid.NewGuid());
+
+            await Assert.ThrowsAsync<WebApiException>(
+                () => account.Client.VerifyCredentials()
+            );
+        }
+    }
+}
index afebef2..00f1135 100644 (file)
@@ -88,14 +88,15 @@ namespace OpenTween.SocialProtocol
                 account.Dispose();
         }
 
-        public ISocialAccount? GetAccountForTab(TabModel tab)
+        public ISocialAccount GetAccountForTab(TabModel tab)
         {
             if (tab.SourceAccountId is { } accountId)
             {
                 if (this.accounts.TryGetValue(accountId, out var account))
                     return account;
 
-                return null;
+                // タブ追加後に設定画面からアカウントの情報を削除した場合
+                return new InvalidAccount(accountId);
             }
 
             return this.Primary;
diff --git a/OpenTween/SocialProtocol/InvalidAccount.cs b/OpenTween/SocialProtocol/InvalidAccount.cs
new file mode 100644 (file)
index 0000000..5a1dbb4
--- /dev/null
@@ -0,0 +1,106 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2024 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+#nullable enable
+
+using System;
+using System.Threading.Tasks;
+using OpenTween.Connection;
+using OpenTween.Models;
+
+namespace OpenTween.SocialProtocol
+{
+    public class InvalidAccount : ISocialAccount
+    {
+        public string AccountType
+            => "InvalidAccount";
+
+        public Guid UniqueKey { get; }
+
+        public PersonId UserId
+            => new TwitterUserId("0");
+
+        public string UserName
+            => "(Unknown account)";
+
+        public IApiConnection Connection { get; } = new InvalidAccountConnection();
+
+        public ISocialProtocolClient Client { get; } = new InvalidAccountClient();
+
+        public bool IsDisposed { get; private set; }
+
+        public InvalidAccount(Guid uniqueKey)
+            => this.UniqueKey = uniqueKey;
+
+        public void Initialize(UserAccount accountSettings, SettingCommon settingCommon)
+        {
+        }
+
+        public void Dispose()
+            => this.IsDisposed = true;
+
+        private class InvalidAccountConnection : IApiConnection
+        {
+            public Task<ApiResponse> SendAsync(IHttpRequest request)
+                => throw new WebApiException("Invalid account");
+
+            public void Dispose()
+            {
+            }
+        }
+
+        private class InvalidAccountClient : ISocialProtocolClient
+        {
+            public Task<UserInfo> VerifyCredentials()
+                => throw this.CreateException();
+
+            public Task<PostClass> GetPostById(PostId postId, bool firstLoad)
+                => throw this.CreateException();
+
+            public Task<TimelineResponse> GetHomeTimeline(int count, IQueryCursor? cursor, bool firstLoad)
+                => throw this.CreateException();
+
+            public Task<TimelineResponse> GetSearchTimeline(string query, string lang, int count, IQueryCursor? cursor, bool firstLoad)
+                => throw this.CreateException();
+
+            public Task<PostClass[]> GetRelatedPosts(PostClass targetPost, bool firstLoad)
+                => throw this.CreateException();
+
+            public Task DeletePost(PostId postId)
+                => throw this.CreateException();
+
+            public Task FavoritePost(PostId postId)
+                => throw this.CreateException();
+
+            public Task UnfavoritePost(PostId postId)
+                => throw this.CreateException();
+
+            public Task<PostClass?> RetweetPost(PostId postId)
+                => throw this.CreateException();
+
+            public Task UnretweetPost(PostId postId)
+                => throw this.CreateException();
+
+            private WebApiException CreateException()
+                => new("Invalid account");
+        }
+    }
+}
index 3748b46..6cb5890 100644 (file)
@@ -122,7 +122,7 @@ namespace OpenTween
             => this.accounts.Primary;
 
         public ISocialAccount CurrentTabAccount
-            => this.accounts.GetAccountForTab(this.CurrentTab) ?? throw new InvalidOperationException("Account not found");
+            => this.accounts.GetAccountForTab(this.CurrentTab);
 
         // Growl呼び出し部
         private readonly GrowlHelper gh = new(ApplicationSettings.ApplicationName);
@@ -1310,7 +1310,7 @@ namespace OpenTween
             try
             {
                 var accountForTab = this.accounts.GetAccountForTab(tab);
-                if (accountForTab == null)
+                if (accountForTab is InvalidAccount)
                     return;
 
                 this.RefreshTasktrayIcon();
@@ -2902,7 +2902,7 @@ namespace OpenTween
                     headerPanel = new GeneralTimelineHeaderPanel
                     {
                         Dock = DockStyle.Top,
-                        HeaderText = account != null ? $"@{account.UserName}: Home" : "",
+                        HeaderText = $"@{account.UserName}: Home",
                     };
                 }
                 // 検索関連の準備