// OpenTween - Client of Twitter // Copyright (c) 2014 spx (@5px) // Copyright (c) 2023 kim_upsilon (@kim_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 , or write to // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, // Boston, MA 02110-1301, USA. using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using Moq; using OpenTween.Api; using OpenTween.Api.DataModel; using Xunit; namespace OpenTween { public class MediaSelectorTest { public MediaSelectorTest() => this.MyCommonSetup(); private void MyCommonSetup() { var mockAssembly = new Mock<_Assembly>(); mockAssembly.Setup(m => m.GetName()).Returns(new AssemblyName("OpenTween")); MyCommon.EntryAssembly = mockAssembly.Object; } [Fact] public void SelectedMediaServiceIndex_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); Assert.Equal("Twitter", mediaSelector.MediaServices[0].Key); Assert.Equal("Imgur", mediaSelector.MediaServices[1].Key); mediaSelector.SelectedMediaServiceName = "Imgur"; Assert.Equal(1, mediaSelector.SelectedMediaServiceIndex); mediaSelector.SelectedMediaServiceName = "Twitter"; Assert.Equal(0, mediaSelector.SelectedMediaServiceIndex); } [Fact] public void SelectMediaService_TwitterTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); Assert.Contains(mediaSelector.MediaServices, x => x.Key == "Twitter"); // 投稿先に Twitter が選択されている Assert.Equal("Twitter", mediaSelector.SelectedMediaServiceName); // 代替テキストが入力可能な状態 Assert.True(mediaSelector.CanUseAltText); } [Fact] public void SelectMediaService_ImgurTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Imgur"); // 投稿先に Imgur が選択されている Assert.Equal("Imgur", mediaSelector.SelectedMediaServiceName); // 代替テキストが入力できない状態 Assert.False(mediaSelector.CanUseAltText); } [Fact] public void AddMediaItem_FilePath_SingleTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); var images = new[] { "Resources/re.gif" }; mediaSelector.AddMediaItemFromFilePath(images); // 画像が 1 つ追加された状態 Assert.Single(mediaSelector.MediaItems); // 1 枚目の画像が表示されている Assert.Equal(0, mediaSelector.SelectedMediaItemIndex); Assert.Equal(Path.GetFullPath("Resources/re.gif"), mediaSelector.SelectedMediaItem!.Path); using var imageStream = File.OpenRead("Resources/re.gif"); using var expectedImage = MemoryImage.CopyFromStream(imageStream); using var actualImage = mediaSelector.SelectedMediaItem.CreateImage(); Assert.Equal(expectedImage, actualImage); } [Fact] public void AddMediaItem_MemoryImageTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); using (var bitmap = new Bitmap(width: 200, height: 200)) mediaSelector.AddMediaItemFromImage(bitmap); // 画像が 1 つ追加された状態 Assert.Single(mediaSelector.MediaItems); // 1 枚目の画像が表示されている Assert.Equal(0, mediaSelector.SelectedMediaItemIndex); Assert.Matches(@"^<>MemoryImage://\d+.png$", mediaSelector.SelectedMediaItem!.Path); using (var bitmap = new Bitmap(width: 200, height: 200)) { using var expectedImage = MemoryImage.CopyFromImage(bitmap); using var actualImage = mediaSelector.SelectedMediaItem.CreateImage(); Assert.Equal(expectedImage, actualImage); } } [Fact] public void AddMediaItem_FilePath_MultipleTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); var images = new[] { "Resources/re.gif", "Resources/re1.png" }; mediaSelector.AddMediaItemFromFilePath(images); // 画像が 2 つ追加された状態 Assert.Equal(2, mediaSelector.MediaItems.Count); // 最後の画像(2 枚目)が表示されている Assert.Equal(1, mediaSelector.SelectedMediaItemIndex); Assert.Equal(Path.GetFullPath("Resources/re1.png"), mediaSelector.SelectedMediaItem!.Path); using var imageStream = File.OpenRead("Resources/re1.png"); using var expectedImage = MemoryImage.CopyFromStream(imageStream); using var actualImage = mediaSelector.SelectedMediaItem.CreateImage(); Assert.Equal(expectedImage, actualImage); } [Fact] public void ClearMediaItems_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); mediaSelector.AddMediaItemFromFilePath(new[] { "Resources/re.gif" }); var mediaItems = mediaSelector.MediaItems.ToArray(); var thumbnailImages = mediaSelector.ThumbnailList.ToArray(); // 表示中の画像 mediaSelector.ClearMediaItems(); Assert.True(mediaItems.All(x => x.IsDisposed)); Assert.True(thumbnailImages.All(x => x.IsDisposed)); } [Fact] public void DetachMediaItems_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); mediaSelector.AddMediaItemFromFilePath(new[] { "Resources/re.gif" }); var thumbnailImages = mediaSelector.ThumbnailList.ToArray(); var detachedMediaItems = mediaSelector.DetachMediaItems(); Assert.Empty(mediaSelector.MediaItems); Assert.True(thumbnailImages.All(x => x.IsDisposed)); // DetachMediaItems で切り離された MediaItem は破棄しない Assert.True(detachedMediaItems.All(x => !x.IsDisposed)); } [Fact] public void SelectedMediaItemChange_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); var images = new[] { "Resources/re.gif", "Resources/re1.png" }; mediaSelector.AddMediaItemFromFilePath(images); mediaSelector.SelectedMediaItemIndex = 0; // 1 ページ目 Assert.Equal(Path.GetFullPath("Resources/re.gif"), mediaSelector.SelectedMediaItem!.Path); using (var imageStream = File.OpenRead("Resources/re.gif")) { using var expectedImage = MemoryImage.CopyFromStream(imageStream); using var actualImage = mediaSelector.SelectedMediaItem.CreateImage(); Assert.Equal(expectedImage, actualImage); } mediaSelector.SelectedMediaItemIndex = 1; // 2 ページ目 Assert.Equal(Path.GetFullPath("Resources/re1.png"), mediaSelector.SelectedMediaItem!.Path); using (var imageStream = File.OpenRead("Resources/re1.png")) { using var expectedImage = MemoryImage.CopyFromStream(imageStream); using var actualImage = mediaSelector.SelectedMediaItem.CreateImage(); Assert.Equal(expectedImage, actualImage); } } [Fact] public void SelectedMediaItemChange_DisposeTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); var images = new[] { "Resources/re.gif", "Resources/re1.png" }; mediaSelector.AddMediaItemFromFilePath(images); // 1 枚目 mediaSelector.SelectedMediaItemIndex = 0; var firstImage = mediaSelector.SelectedMediaItemImage; // 2 枚目 mediaSelector.SelectedMediaItemIndex = 1; var secondImage = mediaSelector.SelectedMediaItemImage; Assert.True(firstImage!.IsDisposed); } [Fact] public void SetSelectedMediaAltText_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); var images = new[] { "Resources/re.gif", "Resources/re1.png" }; mediaSelector.AddMediaItemFromFilePath(images); // 1 ページ目 mediaSelector.SelectedMediaItemIndex = 0; mediaSelector.SetSelectedMediaAltText("Page 1"); // 2 ページ目 mediaSelector.SelectedMediaItemIndex = 1; mediaSelector.SetSelectedMediaAltText("Page 2"); Assert.Equal("Page 1", mediaSelector.MediaItems[0].AltText); Assert.Equal("Page 2", mediaSelector.MediaItems[1].AltText); } [Fact] public void Validate_PassTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); using var mediaItem = TestUtils.CreateDummyMediaItem(); mediaSelector.AddMediaItem(mediaItem); Assert.Equal(MediaSelectorErrorType.None, mediaSelector.Validate(out var rejected)); Assert.Null(rejected); } [Fact] public void Validate_EmptyErrorTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); Assert.Equal( MediaSelectorErrorType.MediaItemNotSet, mediaSelector.Validate(out var rejected) ); Assert.Null(rejected); } [Fact] public void Validate_ServiceNotSelectedErrorTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); using var mediaItem = TestUtils.CreateDummyMediaItem(); mediaSelector.AddMediaItem(mediaItem); Assert.Equal( MediaSelectorErrorType.ServiceNotSelected, mediaSelector.Validate(out var rejected) ); Assert.Null(rejected); } [Fact] public void Validate_ExtensionErrorTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); var mock = new Mock(); mock.Setup(x => x.CreateImage()).Returns(() => TestUtils.CreateDummyImage()); mock.Setup(x => x.Extension).Returns(".exe"); mock.Setup(x => x.Size).Returns(1_000_000); mediaSelector.AddMediaItem(mock.Object); Assert.Equal( MediaSelectorErrorType.UnsupportedFileExtension, mediaSelector.Validate(out var rejected) ); Assert.Same(mock.Object, rejected); } [Fact] public void Validate_FileSizeErrorTest() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.InitializeServices(twitter, TwitterConfiguration.DefaultConfiguration()); mediaSelector.SelectMediaService("Twitter"); var mock = new Mock(); mock.Setup(x => x.CreateImage()).Returns(() => TestUtils.CreateDummyImage()); mock.Setup(x => x.Extension).Returns(".png"); mock.Setup(x => x.Size).Returns(1_000_000_000); // 1GB mediaSelector.AddMediaItem(mock.Object); Assert.Equal( MediaSelectorErrorType.FileSizeExceeded, mediaSelector.Validate(out var rejected) ); Assert.Same(mock.Object, rejected); } [Fact] public void MoveSelectedMediaItemToPrevious_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.AddMediaItemFromFilePath(new[] { "Resources/re.gif", "Resources/re1.png" }); mediaSelector.SelectedMediaItemIndex = 1; mediaSelector.MoveSelectedMediaItemToPrevious(); Assert.Equal("re1.png", mediaSelector.MediaItems[0].Name); Assert.Equal("re.gif", mediaSelector.MediaItems[1].Name); Assert.Equal(0, mediaSelector.SelectedMediaItemIndex); } [Fact] public void MoveSelectedMediaItemToNext_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.AddMediaItemFromFilePath(new[] { "Resources/re.gif", "Resources/re1.png" }); mediaSelector.SelectedMediaItemIndex = 0; mediaSelector.MoveSelectedMediaItemToNext(); Assert.Equal("re1.png", mediaSelector.MediaItems[0].Name); Assert.Equal("re.gif", mediaSelector.MediaItems[1].Name); Assert.Equal(1, mediaSelector.SelectedMediaItemIndex); } [Fact] public void RemoveSelectedMediaItem_Test() { using var twitterApi = new TwitterApi(); using var twitter = new Twitter(twitterApi); using var mediaSelector = new MediaSelector(); mediaSelector.AddMediaItemFromFilePath(new[] { "Resources/re.gif", "Resources/re1.png" }); mediaSelector.SelectedMediaItemIndex = 0; mediaSelector.RemoveSelectedMediaItem(); Assert.Single(mediaSelector.MediaItems); Assert.Equal("re1.png", mediaSelector.MediaItems[0].Name); Assert.Equal(-1, mediaSelector.SelectedMediaItemIndex); } } }