OSDN Git Service

翻訳機能の OTWebClient に依存している箇所を HttpClient に置き換え
authorKimura Youichi <kim.upsilon@bucyou.net>
Mon, 21 Apr 2014 17:18:21 +0000 (02:18 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Sat, 26 Apr 2014 09:44:30 +0000 (18:44 +0900)
OpenTween.Tests/BingTest.cs
OpenTween/AppendSettingDialog.cs
OpenTween/Bing.cs
OpenTween/Tween.cs

index aa79239..b06c558 100644 (file)
@@ -1,5 +1,6 @@
 // OpenTween - Client of Twitter
 // Copyright (c) 2012 the40san <http://sourceforge.jp/users/the40san/>
+//           (c) 2014 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
 // All rights reserved.
 //
 // This file is part of OpenTween.
 // Boston, MA 02110-1301, USA.
 
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
+using System.Net;
+using System.Net.Http;
 using System.Text;
+using System.Threading.Tasks;
+using System.Web;
 using Xunit;
 using Xunit.Extensions;
 
@@ -31,169 +33,81 @@ namespace OpenTween
 {
     /// <summary>
     /// Bingクラスのテストクラス
-    /// Translate(string _from, string _to, string _text, out string buf)のテスト未実装です
     /// </summary>
     public class BingTest
     {
-        List<string> LanguageTable;
-        Bing bing;
-
-        public BingTest()
+        [Fact]
+        public async Task TranslateAsync_Test()
         {
-            bing = new Bing();
-            //リフレクション使ってインスタンスから取得するようにしたい
-            #region 言語テーブル定義
-            LanguageTable = new List<string>() {
-            "af",
-            "sq",
-            "ar-sa",
-            "ar-iq",
-            "ar-eg",
-            "ar-ly",
-            "ar-dz",
-            "ar-ma",
-            "ar-tn",
-            "ar-om",
-            "ar-ye",
-            "ar-sy",
-            "ar-jo",
-            "ar-lb",
-            "ar-kw",
-            "ar-ae",
-            "ar-bh",
-            "ar-qa",
-            "eu",
-            "bg",
-            "be",
-            "ca",
-            "zh-tw",
-            "zh-cn",
-            "zh-hk",
-            "zh-sg",
-            "hr",
-            "cs",
-            "da",
-            "nl",
-            "nl-be",
-            "en",
-            "en-us",
-            "en-gb",
-            "en-au",
-            "en-ca",
-            "en-nz",
-            "en-ie",
-            "en-za",
-            "en-jm",
-            "en",
-            "en-bz",
-            "en-tt",
-            "et",
-            "fo",
-            "fa",
-            "fi",
-            "fr",
-            "fr-be",
-            "fr-ca",
-            "fr-ch",
-            "fr-lu",
-            "gd",
-            "ga",
-            "de",
-            "de-ch",
-            "de-at",
-            "de-lu",
-            "de-li",
-            "el",
-            "he",
-            "hi",
-            "hu",
-            "is",
-            "id",
-            "it",
-            "it-ch",
-            "ja",
-            "ko",
-            "ko",
-            "lv",
-            "lt",
-            "mk",
-            "ms",
-            "mt",
-            "no",
-            "no",
-            "pl",
-            "pt-br",
-            "pt",
-            "rm",
-            "ro",
-            "ro-mo",
-            "ru",
-            "ru-mo",
-            "sz",
-            "sr",
-            "sr",
-            "sk",
-            "sl",
-            "sb",
-            "es",
-            "es-mx",
-            "es-gt",
-            "es-cr",
-            "es-pa",
-            "es-do",
-            "es-ve",
-            "es-co",
-            "es-pe",
-            "es-ar",
-            "es-ec",
-            "es-cl",
-            "es-uy",
-            "es-py",
-            "es-bo",
-            "es-sv",
-            "es-hn",
-            "es-ni",
-            "es-pr",
-            "sx",
-            "sv",
-            "sv-fi",
-            "th",
-            "ts",
-            "tn",
-            "tr",
-            "uk",
-            "ur",
-            "ve",
-            "vi",
-            "xh",
-            "ji",
-            "zu"
-        };
-        #endregion
+            var handler = new HttpMessageHandlerMock();
+            var bing = new Bing(new HttpClient(handler));
 
-        }
+            handler.Enqueue(x =>
+            {
+                Assert.Equal(HttpMethod.Get, x.Method);
+                Assert.Equal("https://api.datamarket.azure.com/Data.ashx/Bing/MicrosoftTranslator/v1/Translate",
+                    x.RequestUri.GetLeftPart(UriPartial.Path));
+
+                var query = HttpUtility.ParseQueryString(x.RequestUri.Query);
+
+                Assert.Equal("'hogehoge'", query["Text"]);
+                Assert.Equal("'ja'", query["To"]);
+                Assert.Equal("Raw", query["$format"]);
 
-        //public bool TranslateTest(string _from, string _to, string _text, out string buf)
-        //{
+                return new HttpResponseMessage(HttpStatusCode.OK)
+                {
+                    Content = new StringContent("<string>ほげほげ</string>"),
+                };
+            });
 
-        //}
+            var translatedText = await bing.TranslateAsync("hogehoge", langFrom: null, langTo: "ja");
+            Assert.Equal("ほげほげ", translatedText);
+
+            Assert.Equal(0, handler.QueueCount);
+        }
 
         [Fact]
-        public void GetLanguageEnumFromIndexTest()
+        public async Task TranslateAsync_HttpErrorTest()
         {
-            Assert.Equal(LanguageTable[0], bing.GetLanguageEnumFromIndex(0));
-            Assert.Equal(LanguageTable[1], bing.GetLanguageEnumFromIndex(1));
-            Assert.Equal(LanguageTable[LanguageTable.Count - 1], bing.GetLanguageEnumFromIndex(LanguageTable.Count - 1));
+            var handler = new HttpMessageHandlerMock();
+            var bing = new Bing(new HttpClient(handler));
+
+            handler.Enqueue(x =>
+            {
+                return new HttpResponseMessage(HttpStatusCode.ServiceUnavailable);
+            });
+
+            await TestUtils.ThrowsAsync<HttpRequestException>(async () =>
+                await bing.TranslateAsync("hogehoge", langFrom: null, langTo: "ja"));
+
+            Assert.Equal(0, handler.QueueCount);
         }
 
-        [Fact]
-        public void GetIndexFromLanguageEnumTest()
+        [Theory]
+        [InlineData("af", 0)]
+        [InlineData("sq", 1)]
+        [InlineData("ja", 67)]
+        public void GetLanguageEnumFromIndex_Test(string expected, int index)
+        {
+            Assert.Equal(expected, Bing.GetLanguageEnumFromIndex(index));
+        }
+
+        [Theory]
+        [InlineData(0, "af")]
+        [InlineData(1, "sq")]
+        [InlineData(67, "ja")]
+        public void GetIndexFromLanguageEnum_Test(int expected, string lang)
         {
-            Assert.Equal(0, bing.GetIndexFromLanguageEnum(LanguageTable[0]));
-            Assert.Equal(1, bing.GetIndexFromLanguageEnum(LanguageTable[1]));
-            Assert.Equal(LanguageTable.Count - 1, bing.GetIndexFromLanguageEnum(LanguageTable[LanguageTable.Count - 1]));
+            Assert.Equal(expected, Bing.GetIndexFromLanguageEnum(lang));
         }
 
+        [Fact]
+        public void CreateBasicAuthHeaderValue_Test()
+        {
+            var value = Bing.CreateBasicAuthHeaderValue("user", "pass");
 
+            Assert.Equal("Basic", value.Scheme);
+            Assert.Equal("user:pass", Encoding.UTF8.GetString(Convert.FromBase64String(value.Parameter)));
+        }
     }
 }
index a352fbc..abac301 100644 (file)
@@ -407,7 +407,7 @@ namespace OpenTween
                 GetEventNotifyFlag(ref _MyEventNotifyFlag, ref _isMyEventNotifyFlag);
                 ForceEventNotify = this.NotifyPanel.CheckForceEventNotify.Checked;
                 FavEventUnread = this.NotifyPanel.CheckFavEventUnread.Checked;
-                TranslateLanguage = (new Bing()).GetLanguageEnumFromIndex(this.CooperatePanel.ComboBoxTranslateLanguage.SelectedIndex);
+                TranslateLanguage = Bing.GetLanguageEnumFromIndex(this.CooperatePanel.ComboBoxTranslateLanguage.SelectedIndex);
                 EventSoundFile = (string)this.NotifyPanel.ComboBoxEventNotifySound.SelectedItem;
                 AutoShortUrlFirst = (MyCommon.UrlConverter)this.ShortUrlPanel.ComboBoxAutoShortUrlFirst.SelectedIndex;
                 TabIconDisp = this.PreviewPanel.chkTabIconDisp.Checked;
@@ -766,7 +766,7 @@ namespace OpenTween
             ApplyEventNotifyFlag(EventNotifyEnabled, EventNotifyFlag, IsMyEventNotifyFlag);
             this.NotifyPanel.CheckForceEventNotify.Checked = ForceEventNotify;
             this.NotifyPanel.CheckFavEventUnread.Checked = FavEventUnread;
-            this.CooperatePanel.ComboBoxTranslateLanguage.SelectedIndex = (new Bing()).GetIndexFromLanguageEnum(TranslateLanguage);
+            this.CooperatePanel.ComboBoxTranslateLanguage.SelectedIndex = Bing.GetIndexFromLanguageEnum(TranslateLanguage);
             SoundFileListup();
             this.ShortUrlPanel.ComboBoxAutoShortUrlFirst.SelectedIndex = (int)AutoShortUrlFirst;
             this.PreviewPanel.chkTabIconDisp.Checked = TabIconDisp;
@@ -1222,7 +1222,7 @@ namespace OpenTween
             set
             {
                 _MyTranslateLanguage = value;
-                this.CooperatePanel.ComboBoxTranslateLanguage.SelectedIndex = (new Bing()).GetIndexFromLanguageEnum(value);
+                this.CooperatePanel.ComboBoxTranslateLanguage.SelectedIndex = Bing.GetIndexFromLanguageEnum(value);
             }
         }
 
index bff930f..3d57cc4 100644 (file)
 
 using System;
 using System.Collections.Generic;
-using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
 using System.Text;
-using System.Net;
-using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Web;
+using System.Xml.Linq;
 
 namespace OpenTween
 {
     public class Bing
     {
-        #region 言語テーブル定義
-        private static readonly List<string> LanguageTable = new List<string>() {
+        private static readonly List<string> LanguageTable = new List<string>
+        {
             "af",
             "sq",
             "ar-sa",
@@ -160,49 +162,63 @@ namespace OpenTween
             "vi",
             "xh",
             "ji",
-            "zu"
+            "zu",
         };
-        #endregion
 
-        #region Translation
-        private const string TranslateUri = "https://api.datamarket.azure.com/Data.ashx/Bing/MicrosoftTranslator/v1/Translate";
+        private static readonly string TranslateUri =
+            "https://api.datamarket.azure.com/Data.ashx/Bing/MicrosoftTranslator/v1/Translate";
+
+        private readonly HttpClient http;
+
+        public Bing(HttpClient http)
+        {
+            this.http = http;
+        }
 
-        public bool Translate(string _from, string _to, string _text, out string buf)
+        /// <summary>
+        /// Microsoft Translator API を使用した翻訳を非同期に行います
+        /// </summary>
+        /// <exception cref="HttpRequestException"/>
+        public async Task<string> TranslateAsync(string text, string langFrom, string langTo)
         {
-            var apiurl = TranslateUri +
-                "?Text=" + Uri.EscapeDataString("'" + _text + "'") +
-                "&To=" + Uri.EscapeDataString("'" + _to + "'") +
-                "&$format=Raw";
+            var param = HttpUtility.ParseQueryString(string.Empty);
+            param["Text"] = "'" + text + "'";
+            param["To"] = "'" + langTo + "'";
+            param["$format"] = "Raw";
+
+            if (langFrom != null)
+                param["From"] = "'" + langFrom + "'";
 
-            using (var client = new OTWebClient())
+            var request = new HttpRequestMessage(HttpMethod.Get, TranslateUri + "?" + param);
+            request.Headers.Authorization = CreateBasicAuthHeaderValue(ApplicationSettings.AzureMarketplaceKey, ApplicationSettings.AzureMarketplaceKey);
+
+            using (var response = await this.http.SendAsync(request).ConfigureAwait(false))
             {
-                client.Credentials = new NetworkCredential(ApplicationSettings.AzureMarketplaceKey, ApplicationSettings.AzureMarketplaceKey);
-                client.Encoding = Encoding.UTF8;
+                response.EnsureSuccessStatusCode();
+
+                var xmlStr = await response.Content.ReadAsStringAsync()
+                    .ConfigureAwait(false);
 
-                try
-                {
-                    var content = client.DownloadString(apiurl);
+                var xdoc = XDocument.Parse(xmlStr);
 
-                    buf = Regex.Replace(content, @"^<string[^>]*>(.*)</string>$", "$1");
-                    return true;
-                }
-                catch (WebException)
-                {
-                    buf = null;
-                    return false;
-                }
+                return xdoc.Root.Value;
             }
         }
 
-        public string GetLanguageEnumFromIndex(int index)
+        public static string GetLanguageEnumFromIndex(int index)
         {
             return LanguageTable[index];
         }
 
-        public int GetIndexFromLanguageEnum(string lang)
+        public static int GetIndexFromLanguageEnum(string lang)
         {
             return LanguageTable.IndexOf(lang);
         }
-        #endregion
+
+        internal static AuthenticationHeaderValue CreateBasicAuthHeaderValue(string user, string pass)
+        {
+            var paramBytes = Encoding.UTF8.GetBytes(user + ":" + pass);
+            return new AuthenticationHeaderValue("Basic", Convert.ToBase64String(paramBytes));
+        }
     }
 }
index d2a0229..9ff4a31 100644 (file)
@@ -13195,34 +13195,38 @@ namespace OpenTween
             OpenUriAsync(MyCommon.TwitterUrl + tw.Username);
         }
 
-        private void doTranslation(string str)
+        private async Task doTranslation(string str)
         {
-            Bing _bing = new Bing();
-            string buf = "";
-            if (string.IsNullOrEmpty(str)) return;
-            string srclng = "";
-            string dstlng = SettingDialog.TranslateLanguage;
-            string msg = "";
-            if (srclng != dstlng && _bing.Translate("", dstlng, str, out buf))
+            if (string.IsNullOrEmpty(str))
+                return;
+
+            var bing = new Bing(this.http);
+            try
             {
-                PostBrowser.DocumentText = createDetailHtml(buf);
+                var translatedText = await bing.TranslateAsync(str,
+                    langFrom: null,
+                    langTo: this.SettingDialog.TranslateLanguage);
+
+                this.PostBrowser.DocumentText = translatedText;
             }
-            else
+            catch (HttpRequestException e)
             {
-                if (msg.StartsWith("Err:"))
-                    StatusLabel.Text = msg;
+                this.StatusLabel.Text = "Err:" + e.Message;
             }
         }
 
-        private void TranslationToolStripMenuItem_Click(object sender, EventArgs e)
+        private async void TranslationToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            if (!this.ExistCurrentPost) return;
-            doTranslation(_curPost.TextFromApi);
+            if (!this.ExistCurrentPost)
+                return;
+
+            await this.doTranslation(this._curPost.TextFromApi);
         }
 
-        private void SelectionTranslationToolStripMenuItem_Click(object sender, EventArgs e)
+        private async void SelectionTranslationToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            doTranslation(WebBrowser_GetSelectionText(ref PostBrowser));
+            var text = this.WebBrowser_GetSelectionText(ref this.PostBrowser);
+            await this.doTranslation(text);
         }
 
         private bool ExistCurrentPost