aboutsummaryrefslogtreecommitdiff
path: root/Timeline.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'Timeline.Tests')
-rw-r--r--Timeline.Tests/Controllers/TokenControllerTest.cs4
-rw-r--r--Timeline.Tests/Controllers/UserControllerTest.cs4
-rw-r--r--Timeline.Tests/Helpers/UseCultureAttribute.cs91
-rw-r--r--Timeline.Tests/IntegratedTests/I18nTest.cs63
-rw-r--r--Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs25
-rw-r--r--Timeline.Tests/UsernameValidatorUnitTest.cs8
6 files changed, 160 insertions, 35 deletions
diff --git a/Timeline.Tests/Controllers/TokenControllerTest.cs b/Timeline.Tests/Controllers/TokenControllerTest.cs
index 53b6c606..4a08ca0f 100644
--- a/Timeline.Tests/Controllers/TokenControllerTest.cs
+++ b/Timeline.Tests/Controllers/TokenControllerTest.cs
@@ -25,9 +25,7 @@ namespace Timeline.Tests.Controllers
public TokenControllerTest()
{
- _controller = new TokenController(_mockUserService.Object,
- NullLogger<TokenController>.Instance, _mockClock,
- TestStringLocalizerFactory.Create().Create<TokenController>());
+ _controller = new TokenController(_mockUserService.Object, NullLogger<TokenController>.Instance, _mockClock);
}
public void Dispose()
diff --git a/Timeline.Tests/Controllers/UserControllerTest.cs b/Timeline.Tests/Controllers/UserControllerTest.cs
index 781ec111..a9cce970 100644
--- a/Timeline.Tests/Controllers/UserControllerTest.cs
+++ b/Timeline.Tests/Controllers/UserControllerTest.cs
@@ -27,9 +27,7 @@ namespace Timeline.Tests.Controllers
public UserControllerTest()
{
- _controller = new UserController(NullLogger<UserController>.Instance,
- _mockUserService.Object,
- TestStringLocalizerFactory.Create());
+ _controller = new UserController(NullLogger<UserController>.Instance, _mockUserService.Object);
}
public void Dispose()
diff --git a/Timeline.Tests/Helpers/UseCultureAttribute.cs b/Timeline.Tests/Helpers/UseCultureAttribute.cs
new file mode 100644
index 00000000..f0064c01
--- /dev/null
+++ b/Timeline.Tests/Helpers/UseCultureAttribute.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using Xunit.Sdk;
+
+// Copied from https://github.com/xunit/samples.xunit/blob/master/UseCulture/UseCultureAttribute.cs
+
+/// <summary>
+/// Apply this attribute to your test method to replace the
+/// <see cref="Thread.CurrentThread" /> <see cref="CultureInfo.CurrentCulture" /> and
+/// <see cref="CultureInfo.CurrentUICulture" /> with another culture.
+/// </summary>
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+public class UseCultureAttribute : BeforeAfterTestAttribute
+{
+ readonly Lazy<CultureInfo> culture;
+ readonly Lazy<CultureInfo> uiCulture;
+
+ CultureInfo originalCulture;
+ CultureInfo originalUICulture;
+
+ /// <summary>
+ /// Replaces the culture and UI culture of the current thread with
+ /// <paramref name="culture" />
+ /// </summary>
+ /// <param name="culture">The name of the culture.</param>
+ /// <remarks>
+ /// <para>
+ /// This constructor overload uses <paramref name="culture" /> for both
+ /// <see cref="Culture" /> and <see cref="UICulture" />.
+ /// </para>
+ /// </remarks>
+ public UseCultureAttribute(string culture)
+ : this(culture, culture) { }
+
+ /// <summary>
+ /// Replaces the culture and UI culture of the current thread with
+ /// <paramref name="culture" /> and <paramref name="uiCulture" />
+ /// </summary>
+ /// <param name="culture">The name of the culture.</param>
+ /// <param name="uiCulture">The name of the UI culture.</param>
+ public UseCultureAttribute(string culture, string uiCulture)
+ {
+ this.culture = new Lazy<CultureInfo>(() => new CultureInfo(culture, false));
+ this.uiCulture = new Lazy<CultureInfo>(() => new CultureInfo(uiCulture, false));
+ }
+
+ /// <summary>
+ /// Gets the culture.
+ /// </summary>
+ public CultureInfo Culture { get { return culture.Value; } }
+
+ /// <summary>
+ /// Gets the UI culture.
+ /// </summary>
+ public CultureInfo UICulture { get { return uiCulture.Value; } }
+
+ /// <summary>
+ /// Stores the current <see cref="Thread.CurrentPrincipal" />
+ /// <see cref="CultureInfo.CurrentCulture" /> and <see cref="CultureInfo.CurrentUICulture" />
+ /// and replaces them with the new cultures defined in the constructor.
+ /// </summary>
+ /// <param name="methodUnderTest">The method under test</param>
+ public override void Before(MethodInfo methodUnderTest)
+ {
+ originalCulture = Thread.CurrentThread.CurrentCulture;
+ originalUICulture = Thread.CurrentThread.CurrentUICulture;
+
+ Thread.CurrentThread.CurrentCulture = Culture;
+ Thread.CurrentThread.CurrentUICulture = UICulture;
+
+ CultureInfo.CurrentCulture.ClearCachedData();
+ CultureInfo.CurrentUICulture.ClearCachedData();
+ }
+
+ /// <summary>
+ /// Restores the original <see cref="CultureInfo.CurrentCulture" /> and
+ /// <see cref="CultureInfo.CurrentUICulture" /> to <see cref="Thread.CurrentPrincipal" />
+ /// </summary>
+ /// <param name="methodUnderTest">The method under test</param>
+ public override void After(MethodInfo methodUnderTest)
+ {
+ Thread.CurrentThread.CurrentCulture = originalCulture;
+ Thread.CurrentThread.CurrentUICulture = originalUICulture;
+
+ CultureInfo.CurrentCulture.ClearCachedData();
+ CultureInfo.CurrentUICulture.ClearCachedData();
+ }
+}
diff --git a/Timeline.Tests/IntegratedTests/I18nTest.cs b/Timeline.Tests/IntegratedTests/I18nTest.cs
new file mode 100644
index 00000000..67bbea5c
--- /dev/null
+++ b/Timeline.Tests/IntegratedTests/I18nTest.cs
@@ -0,0 +1,63 @@
+using Microsoft.AspNetCore.Mvc.Testing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading.Tasks;
+using Timeline.Tests.Helpers;
+using Xunit;
+using FluentAssertions;
+
+namespace Timeline.Tests.IntegratedTests
+{
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1054:Uri parameters should not be strings")]
+ public class I18nTest : IClassFixture<WebApplicationFactory<Startup>>, IDisposable
+ {
+ private readonly TestApplication _testApp;
+ private readonly HttpClient _client;
+
+ public I18nTest(WebApplicationFactory<Startup> factory)
+ {
+ _testApp = new TestApplication(factory);
+ _client = _testApp.Factory.CreateDefaultClient();
+ }
+
+ public void Dispose()
+ {
+ _client.Dispose();
+ _testApp.Dispose();
+ }
+
+ private const string DirectUrl = "testing/i18n/direct";
+ private const string LocalizerUrl = "testing/i18n/localizer";
+
+ [Theory]
+ [InlineData(DirectUrl)]
+ [InlineData(LocalizerUrl)]
+ public async Task DefaultShouldReturnEnglish(string url)
+ {
+ (await _client.GetStringAsync(url)).Should().ContainEquivalentOf("English");
+ }
+
+ [Theory]
+ [InlineData(DirectUrl, "en", true)]
+ [InlineData(LocalizerUrl, "en", true)]
+ [InlineData(DirectUrl, "en-US", true)]
+ [InlineData(LocalizerUrl, "en-US", true)]
+ [InlineData(DirectUrl, "zh", false)]
+ [InlineData(LocalizerUrl, "zh", false)]
+ public async Task ShouldWork(string url, string acceptLanguage, bool english)
+ {
+ var request = new HttpRequestMessage
+ {
+ Method = HttpMethod.Get,
+ RequestUri = new Uri(url, UriKind.RelativeOrAbsolute)
+ };
+ request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(acceptLanguage));
+ var body = await (await _client.SendAsync(request)).Content.ReadAsStringAsync();
+ body.Should().ContainEquivalentOf(english ? "English" : "中文");
+ request.Dispose();
+ }
+ }
+}
diff --git a/Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs b/Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs
deleted file mode 100644
index 4084dd8f..00000000
--- a/Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using Microsoft.Extensions.Localization;
-using Microsoft.Extensions.Logging.Abstractions;
-using Microsoft.Extensions.Options;
-
-namespace Timeline.Tests.Mock.Services
-{
- internal static class TestStringLocalizerFactory
- {
- internal static IStringLocalizerFactory Create()
- {
- return new ResourceManagerStringLocalizerFactory(
- Options.Create(new LocalizationOptions()
- {
- ResourcesPath = "Resource"
- }),
- NullLoggerFactory.Instance
- );
- }
-
- internal static IStringLocalizer<T> Create<T>(this IStringLocalizerFactory factory)
- {
- return new StringLocalizer<T>(factory);
- }
- }
-}
diff --git a/Timeline.Tests/UsernameValidatorUnitTest.cs b/Timeline.Tests/UsernameValidatorUnitTest.cs
index 283e18e2..d02367be 100644
--- a/Timeline.Tests/UsernameValidatorUnitTest.cs
+++ b/Timeline.Tests/UsernameValidatorUnitTest.cs
@@ -4,6 +4,7 @@ using Xunit;
namespace Timeline.Tests
{
+ [UseCulture("en")]
public class UsernameValidatorUnitTest : IClassFixture<UsernameValidator>
{
private readonly UsernameValidator _validator;
@@ -15,9 +16,9 @@ namespace Timeline.Tests
private string FailAndMessage(string username)
{
- var (result, messageGenerator) = _validator.Validate(username);
+ var (result, message) = _validator.Validate(username);
result.Should().BeFalse();
- return messageGenerator(null);
+ return message;
}
[Fact]
@@ -29,9 +30,8 @@ namespace Timeline.Tests
[Fact]
public void NotString()
{
- var (result, messageGenerator) = _validator.Validate(123);
+ var (result, message) = _validator.Validate(123);
result.Should().BeFalse();
- var message = messageGenerator(null);
message.Should().ContainEquivalentOf("type");
}