// OpenTween - Client of Twitter
// Copyright (c) 2012 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.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Moq;
using OpenTween.Models;
using OpenTween.Thumbnail;
using OpenTween.Thumbnail.Services;
using Xunit;
using Xunit.Extensions;
namespace OpenTween
{
public class TweetThumbnailTest
{
private class TestThumbnailService : IThumbnailService
{
private readonly Regex regex;
private readonly string replaceUrl;
private readonly string? replaceTooltip;
public TestThumbnailService(string pattern, string replaceUrl, string? replaceTooltip)
{
this.regex = new Regex(pattern);
this.replaceUrl = replaceUrl;
this.replaceTooltip = replaceTooltip;
}
public override async Task GetThumbnailInfoAsync(string url, PostClass post, CancellationToken token)
{
var match = this.regex.Match(url);
if (!match.Success) return null;
if (url.StartsWith("http://slow.example.com/", StringComparison.Ordinal))
await Task.Delay(1000, token).ConfigureAwait(false);
return new MockThumbnailInfo
{
MediaPageUrl = url,
ThumbnailImageUrl = match.Result(this.replaceUrl),
TooltipText = this.replaceTooltip != null ? match.Result(this.replaceTooltip) : null,
};
}
private class MockThumbnailInfo : ThumbnailInfo
{
public override Task LoadThumbnailImageAsync(HttpClient http, CancellationToken cancellationToken)
=> Task.FromResult(TestUtils.CreateDummyImage());
}
}
public TweetThumbnailTest()
=> this.MyCommonSetup();
private ThumbnailGenerator CreateThumbnailGenerator()
{
var imgAzyobuziNet = new ImgAzyobuziNet(autoupdate: false);
var thumbGenerator = new ThumbnailGenerator(imgAzyobuziNet);
thumbGenerator.Services.Clear();
thumbGenerator.Services.AddRange(new[]
{
new TestThumbnailService(@"^https?://foo.example.com/(.+)$", @"http://img.example.com/${1}.png", null),
new TestThumbnailService(@"^https?://bar.example.com/(.+)$", @"http://img.example.com/${1}.png", @"${1}"),
new TestThumbnailService(@"^https?://slow.example.com/(.+)$", @"http://img.example.com/${1}.png", null),
});
return thumbGenerator;
}
private void MyCommonSetup()
{
var mockAssembly = new Mock<_Assembly>();
mockAssembly.Setup(m => m.GetName()).Returns(new AssemblyName("OpenTween"));
MyCommon.EntryAssembly = mockAssembly.Object;
}
[Fact]
public void CreatePictureBoxTest()
{
using var thumbBox = new TweetThumbnail();
var method = typeof(TweetThumbnail).GetMethod("CreatePictureBox", BindingFlags.Instance | BindingFlags.NonPublic);
var picbox = method.Invoke(thumbBox, new[] { "pictureBox1" }) as PictureBox;
Assert.NotNull(picbox);
Assert.Equal("pictureBox1", picbox!.Name);
Assert.Equal(PictureBoxSizeMode.Zoom, picbox.SizeMode);
Assert.False(picbox.WaitOnLoad);
Assert.Equal(DockStyle.Fill, picbox.Dock);
picbox.Dispose();
}
[Fact]
public async Task CancelAsyncTest()
{
var post = new PostClass
{
TextFromApi = "てすと http://slow.example.com/abcd",
Media = new List
{
new MediaInfo("http://slow.example.com/abcd"),
},
};
using var thumbbox = new TweetThumbnail();
thumbbox.Initialize(this.CreateThumbnailGenerator());
using var tokenSource = new CancellationTokenSource();
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
var task = thumbbox.ShowThumbnailAsync(post, tokenSource.Token);
tokenSource.Cancel();
await Assert.ThrowsAnyAsync(async () => await task);
Assert.True(task.IsCanceled);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
public void SetThumbnailCountTest(int count)
{
using var thumbbox = new TweetThumbnail();
thumbbox.Initialize(this.CreateThumbnailGenerator());
var method = typeof(TweetThumbnail).GetMethod("SetThumbnailCount", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(thumbbox, new[] { (object)count });
Assert.Equal(count, thumbbox.PictureBox.Count);
var num = 0;
foreach (var picbox in thumbbox.PictureBox)
{
Assert.Equal("pictureBox" + num, picbox.Name);
num++;
}
Assert.Equal(thumbbox.PictureBox, thumbbox.panelPictureBox.Controls.Cast());
Assert.Equal(0, thumbbox.scrollBar.Minimum);
if (count == 0)
Assert.Equal(0, thumbbox.scrollBar.Maximum);
else
Assert.Equal(count - 1, thumbbox.scrollBar.Maximum);
}
[Fact]
public async Task ShowThumbnailAsyncTest()
{
var post = new PostClass
{
TextFromApi = "てすと http://foo.example.com/abcd",
Media = new List
{
new MediaInfo("http://foo.example.com/abcd"),
},
};
using var thumbbox = new TweetThumbnail();
thumbbox.Initialize(this.CreateThumbnailGenerator());
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
await thumbbox.ShowThumbnailAsync(post);
Assert.Equal(0, thumbbox.scrollBar.Maximum);
Assert.False(thumbbox.scrollBar.Enabled);
Assert.Single(thumbbox.PictureBox);
Assert.NotNull(thumbbox.PictureBox[0].Image);
Assert.IsAssignableFrom(thumbbox.PictureBox[0].Tag);
var thumbinfo = (ThumbnailInfo)thumbbox.PictureBox[0].Tag;
Assert.Equal("http://foo.example.com/abcd", thumbinfo.MediaPageUrl);
Assert.Equal("http://img.example.com/abcd.png", thumbinfo.ThumbnailImageUrl);
Assert.Equal("", thumbbox.toolTip.GetToolTip(thumbbox.PictureBox[0]));
}
[Fact]
public async Task ShowThumbnailAsyncTest2()
{
var post = new PostClass
{
TextFromApi = "てすと http://foo.example.com/abcd http://bar.example.com/efgh",
Media = new List
{
new MediaInfo("http://foo.example.com/abcd"),
new MediaInfo("http://bar.example.com/efgh"),
},
};
using var thumbbox = new TweetThumbnail();
thumbbox.Initialize(this.CreateThumbnailGenerator());
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
await thumbbox.ShowThumbnailAsync(post);
Assert.Equal(1, thumbbox.scrollBar.Maximum);
Assert.True(thumbbox.scrollBar.Enabled);
Assert.Equal(2, thumbbox.PictureBox.Count);
Assert.NotNull(thumbbox.PictureBox[0].Image);
Assert.NotNull(thumbbox.PictureBox[1].Image);
Assert.IsAssignableFrom(thumbbox.PictureBox[0].Tag);
var thumbinfo = (ThumbnailInfo)thumbbox.PictureBox[0].Tag;
Assert.Equal("http://foo.example.com/abcd", thumbinfo.MediaPageUrl);
Assert.Equal("http://img.example.com/abcd.png", thumbinfo.ThumbnailImageUrl);
Assert.IsAssignableFrom(thumbbox.PictureBox[1].Tag);
thumbinfo = (ThumbnailInfo)thumbbox.PictureBox[1].Tag;
Assert.Equal("http://bar.example.com/efgh", thumbinfo.MediaPageUrl);
Assert.Equal("http://img.example.com/efgh.png", thumbinfo.ThumbnailImageUrl);
Assert.Equal("", thumbbox.toolTip.GetToolTip(thumbbox.PictureBox[0]));
Assert.Equal("efgh", thumbbox.toolTip.GetToolTip(thumbbox.PictureBox[1]));
}
[Fact]
public async Task ThumbnailLoadingEventTest()
{
using var thumbbox = new TweetThumbnail();
thumbbox.Initialize(this.CreateThumbnailGenerator());
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
var post = new PostClass
{
TextFromApi = "てすと",
Media = new List
{
},
};
await TestUtils.NotRaisesAsync(
x => thumbbox.ThumbnailLoading += x,
x => thumbbox.ThumbnailLoading -= x,
() => thumbbox.ShowThumbnailAsync(post)
);
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
var post2 = new PostClass
{
TextFromApi = "てすと http://foo.example.com/abcd",
Media = new List
{
new MediaInfo("http://foo.example.com/abcd"),
},
};
await Assert.RaisesAsync(
x => thumbbox.ThumbnailLoading += x,
x => thumbbox.ThumbnailLoading -= x,
() => thumbbox.ShowThumbnailAsync(post2)
);
}
[Fact]
public async Task ScrollTest()
{
var post = new PostClass
{
TextFromApi = "てすと http://foo.example.com/abcd http://foo.example.com/efgh",
Media = new List
{
new MediaInfo("http://foo.example.com/abcd"),
new MediaInfo("http://foo.example.com/efgh"),
},
};
using var thumbbox = new TweetThumbnail();
thumbbox.Initialize(this.CreateThumbnailGenerator());
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
await thumbbox.ShowThumbnailAsync(post);
Assert.Equal(0, thumbbox.scrollBar.Minimum);
Assert.Equal(1, thumbbox.scrollBar.Maximum);
thumbbox.scrollBar.Value = 0;
thumbbox.ScrollDown();
Assert.Equal(1, thumbbox.scrollBar.Value);
Assert.False(thumbbox.PictureBox[0].Visible);
Assert.True(thumbbox.PictureBox[1].Visible);
thumbbox.ScrollDown();
Assert.Equal(1, thumbbox.scrollBar.Value);
Assert.False(thumbbox.PictureBox[0].Visible);
Assert.True(thumbbox.PictureBox[1].Visible);
thumbbox.ScrollUp();
Assert.Equal(0, thumbbox.scrollBar.Value);
Assert.True(thumbbox.PictureBox[0].Visible);
Assert.False(thumbbox.PictureBox[1].Visible);
thumbbox.ScrollUp();
Assert.Equal(0, thumbbox.scrollBar.Value);
Assert.True(thumbbox.PictureBox[0].Visible);
Assert.False(thumbbox.PictureBox[1].Visible);
}
}
}