aboutsummaryrefslogtreecommitdiff
path: root/Timeline.Tests/Helpers
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-11-20 00:28:53 +0800
committercrupest <crupest@outlook.com>2019-11-20 00:28:53 +0800
commita72960e54a89bd31dcb8be8f52e097007dfd23e5 (patch)
tree55eaf43bda897148b0fa8a65406e7289aed3832e /Timeline.Tests/Helpers
parentf3c7912caec2e9eee8a685d8751894f357528a71 (diff)
downloadtimeline-a72960e54a89bd31dcb8be8f52e097007dfd23e5.tar.gz
timeline-a72960e54a89bd31dcb8be8f52e097007dfd23e5.tar.bz2
timeline-a72960e54a89bd31dcb8be8f52e097007dfd23e5.zip
Clean and refactor tests.
Diffstat (limited to 'Timeline.Tests/Helpers')
-rw-r--r--Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs75
-rw-r--r--Timeline.Tests/Helpers/MockUser.cs24
-rw-r--r--Timeline.Tests/Helpers/PrincipalHelper.cs (renamed from Timeline.Tests/Helpers/Authentication/PrincipalHelper.cs)46
-rw-r--r--Timeline.Tests/Helpers/TestApplication.cs2
-rw-r--r--Timeline.Tests/Helpers/TestClock.cs15
-rw-r--r--Timeline.Tests/Helpers/TestDatabase.cs89
-rw-r--r--Timeline.Tests/Helpers/UseCultureAttribute.cs143
7 files changed, 224 insertions, 170 deletions
diff --git a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs b/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs
deleted file mode 100644
index 4048bb73..00000000
--- a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using Microsoft.AspNetCore.Mvc.Testing;
-using System;
-using System.Net.Http;
-using System.Threading.Tasks;
-using Timeline.Models.Http;
-using Timeline.Tests.Mock.Data;
-
-namespace Timeline.Tests.Helpers.Authentication
-{
- public enum AuthType
- {
- None,
- User,
- Admin
- }
-
- public static class AuthenticationExtensions
- {
- private const string CreateTokenUrl = "/token/create";
-
- public static async Task<CreateTokenResponse> CreateUserTokenAsync(this HttpClient client, string username, string password, int? expireOffset = null)
- {
- var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = username, Password = password, Expire = expireOffset });
- return response.Should().HaveStatusCode(200)
- .And.HaveJsonBody<CreateTokenResponse>().Which;
- }
-
- public static async Task<HttpClient> CreateClientWithCredential<T>(this WebApplicationFactory<T> factory, string username, string password) where T : class
- {
- var client = factory.CreateDefaultClient();
- var token = (await client.CreateUserTokenAsync(username, password)).Token;
- client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
- return client;
- }
-
- public static Task<HttpClient> CreateClientAs<T>(this WebApplicationFactory<T> factory, MockUser user) where T : class
- {
- return CreateClientWithCredential(factory, user.Username, user.Password);
- }
-
- public static Task<HttpClient> CreateClientAsUser<T>(this WebApplicationFactory<T> factory) where T : class
- {
- return factory.CreateClientAs(MockUser.User);
- }
-
- public static Task<HttpClient> CreateClientAsAdmin<T>(this WebApplicationFactory<T> factory) where T : class
- {
- return factory.CreateClientAs(MockUser.Admin);
- }
-
- public static Task<HttpClient> CreateClientAs<T>(this WebApplicationFactory<T> factory, AuthType authType) where T : class
- {
- return authType switch
- {
- AuthType.None => Task.FromResult(factory.CreateDefaultClient()),
- AuthType.User => factory.CreateClientAsUser(),
- AuthType.Admin => factory.CreateClientAsAdmin(),
- _ => throw new InvalidOperationException("Unknown auth type.")
- };
- }
-
- public static MockUser GetMockUser(this AuthType authType)
- {
- return authType switch
- {
- AuthType.None => null,
- AuthType.User => MockUser.User,
- AuthType.Admin => MockUser.Admin,
- _ => throw new InvalidOperationException("Unknown auth type.")
- };
- }
-
- public static string GetUsername(this AuthType authType) => authType.GetMockUser().Username;
- }
-}
diff --git a/Timeline.Tests/Helpers/MockUser.cs b/Timeline.Tests/Helpers/MockUser.cs
new file mode 100644
index 00000000..8d738525
--- /dev/null
+++ b/Timeline.Tests/Helpers/MockUser.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using Timeline.Models;
+
+namespace Timeline.Tests.Helpers
+{
+ public class MockUser
+ {
+ public MockUser(string username, string password, bool administrator)
+ {
+ Info = new UserInfo(username, administrator);
+ Password = password;
+ }
+
+ public UserInfo Info { get; set; }
+ public string Username => Info.Username;
+ public string Password { get; set; }
+ public bool Administrator => Info.Administrator;
+
+ public static MockUser User { get; } = new MockUser("user", "userpassword", false);
+ public static MockUser Admin { get; } = new MockUser("admin", "adminpassword", true);
+
+ public static IReadOnlyList<UserInfo> UserInfoList { get; } = new List<UserInfo> { User.Info, Admin.Info };
+ }
+}
diff --git a/Timeline.Tests/Helpers/Authentication/PrincipalHelper.cs b/Timeline.Tests/Helpers/PrincipalHelper.cs
index 214472a2..89f3f7b1 100644
--- a/Timeline.Tests/Helpers/Authentication/PrincipalHelper.cs
+++ b/Timeline.Tests/Helpers/PrincipalHelper.cs
@@ -1,23 +1,23 @@
-using System.Linq;
-using System.Security.Claims;
-using Timeline.Models;
-
-namespace Timeline.Tests.Helpers.Authentication
-{
- public static class PrincipalHelper
- {
- internal const string AuthScheme = "TESTAUTH";
-
- internal static ClaimsPrincipal Create(string username, bool administrator)
- {
- var identity = new ClaimsIdentity(AuthScheme);
- identity.AddClaim(new Claim(identity.NameClaimType, username, ClaimValueTypes.String));
- identity.AddClaims(UserRoleConvert.ToArray(administrator).Select(role => new Claim(identity.RoleClaimType, role, ClaimValueTypes.String)));
-
- var principal = new ClaimsPrincipal();
- principal.AddIdentity(identity);
-
- return principal;
- }
- }
-}
+using System.Linq;
+using System.Security.Claims;
+using Timeline.Models;
+
+namespace Timeline.Tests.Helpers
+{
+ public static class PrincipalHelper
+ {
+ internal const string AuthScheme = "TESTAUTH";
+
+ internal static ClaimsPrincipal Create(string username, bool administrator)
+ {
+ var identity = new ClaimsIdentity(AuthScheme);
+ identity.AddClaim(new Claim(identity.NameClaimType, username, ClaimValueTypes.String));
+ identity.AddClaims(UserRoleConvert.ToArray(administrator).Select(role => new Claim(identity.RoleClaimType, role, ClaimValueTypes.String)));
+
+ var principal = new ClaimsPrincipal();
+ principal.AddIdentity(identity);
+
+ return principal;
+ }
+ }
+}
diff --git a/Timeline.Tests/Helpers/TestApplication.cs b/Timeline.Tests/Helpers/TestApplication.cs
index 5862f452..a624da6b 100644
--- a/Timeline.Tests/Helpers/TestApplication.cs
+++ b/Timeline.Tests/Helpers/TestApplication.cs
@@ -1,10 +1,8 @@
using Microsoft.AspNetCore.Mvc.Testing;
-using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using Timeline.Entities;
-using Timeline.Tests.Mock.Data;
namespace Timeline.Tests.Helpers
{
diff --git a/Timeline.Tests/Helpers/TestClock.cs b/Timeline.Tests/Helpers/TestClock.cs
new file mode 100644
index 00000000..12b320d3
--- /dev/null
+++ b/Timeline.Tests/Helpers/TestClock.cs
@@ -0,0 +1,15 @@
+using System;
+using Timeline.Services;
+
+namespace Timeline.Tests.Helpers
+{
+ public class TestClock : IClock
+ {
+ public DateTime? MockCurrentTime { get; set; } = null;
+
+ public DateTime GetCurrentTime()
+ {
+ return MockCurrentTime.GetValueOrDefault(DateTime.Now);
+ }
+ }
+}
diff --git a/Timeline.Tests/Helpers/TestDatabase.cs b/Timeline.Tests/Helpers/TestDatabase.cs
new file mode 100644
index 00000000..10224c27
--- /dev/null
+++ b/Timeline.Tests/Helpers/TestDatabase.cs
@@ -0,0 +1,89 @@
+using Microsoft.Data.Sqlite;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Timeline.Entities;
+using Timeline.Models;
+using Timeline.Services;
+
+namespace Timeline.Tests.Helpers
+{
+ public class TestDatabase : IDisposable
+ {
+ // currently password service is thread safe, so we share a static one.
+ private static PasswordService PasswordService { get; } = new PasswordService();
+
+ private static User CreateEntityFromMock(MockUser user)
+ {
+ return new User
+ {
+ Name = user.Username,
+ EncryptedPassword = PasswordService.HashPassword(user.Password),
+ RoleString = UserRoleConvert.ToString(user.Administrator),
+ Avatar = null
+ };
+ }
+
+ private static IEnumerable<User> CreateDefaultMockEntities()
+ {
+ // emmmmmmm. Never reuse the user instances because EF Core uses them, which will cause strange things.
+ yield return CreateEntityFromMock(MockUser.User);
+ yield return CreateEntityFromMock(MockUser.Admin);
+ }
+
+ private static void InitDatabase(DatabaseContext context)
+ {
+ context.Database.EnsureCreated();
+ context.Users.AddRange(CreateDefaultMockEntities());
+ context.SaveChanges();
+ }
+
+ public SqliteConnection Connection { get; }
+ public DatabaseContext Context { get; }
+
+ public TestDatabase()
+ {
+ Connection = new SqliteConnection("Data Source=:memory:;");
+ Connection.Open();
+
+ var options = new DbContextOptionsBuilder<DatabaseContext>()
+ .UseSqlite(Connection)
+ .Options;
+
+ Context = new DatabaseContext(options);
+
+ InitDatabase(Context);
+ }
+
+ private List<MockUser> _extraMockUsers;
+
+ public IReadOnlyList<MockUser> ExtraMockUsers => _extraMockUsers;
+
+ public void CreateExtraMockUsers(int count)
+ {
+ if (count <= 0)
+ throw new ArgumentOutOfRangeException(nameof(count), count, "Additional user count must be bigger than 0.");
+ if (_extraMockUsers != null)
+ throw new InvalidOperationException("Already create mock users.");
+
+ _extraMockUsers = new List<MockUser>();
+ for (int i = 0; i < count; i++)
+ {
+ _extraMockUsers.Add(new MockUser($"user{i}", $"password", false));
+ }
+
+ Context.AddRange(_extraMockUsers.Select(u => CreateEntityFromMock(u)));
+ Context.SaveChanges();
+ }
+
+ public void Dispose()
+ {
+ Context.Dispose();
+
+ Connection.Close();
+ Connection.Dispose();
+ }
+
+ }
+}
diff --git a/Timeline.Tests/Helpers/UseCultureAttribute.cs b/Timeline.Tests/Helpers/UseCultureAttribute.cs
index f0064c01..017d77a8 100644
--- a/Timeline.Tests/Helpers/UseCultureAttribute.cs
+++ b/Timeline.Tests/Helpers/UseCultureAttribute.cs
@@ -1,91 +1,94 @@
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
+namespace Timeline.Tests.Helpers
{
- readonly Lazy<CultureInfo> culture;
- readonly Lazy<CultureInfo> uiCulture;
-
- CultureInfo originalCulture;
- CultureInfo originalUICulture;
+ // Copied from https://github.com/xunit/samples.xunit/blob/master/UseCulture/UseCultureAttribute.cs
/// <summary>
- /// Replaces the culture and UI culture of the current thread with
- /// <paramref name="culture" />
+ /// 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>
- /// <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)
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+ public class UseCultureAttribute : BeforeAfterTestAttribute
{
- this.culture = new Lazy<CultureInfo>(() => new CultureInfo(culture, false));
- this.uiCulture = new Lazy<CultureInfo>(() => new CultureInfo(uiCulture, false));
- }
+ readonly Lazy<CultureInfo> culture;
+ readonly Lazy<CultureInfo> uiCulture;
- /// <summary>
- /// Gets the culture.
- /// </summary>
- public CultureInfo Culture { get { return culture.Value; } }
+ CultureInfo originalCulture;
+ CultureInfo originalUICulture;
- /// <summary>
- /// Gets the UI culture.
- /// </summary>
- public CultureInfo UICulture { get { return uiCulture.Value; } }
+ /// <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>
- /// 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;
+ /// <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));
+ }
- Thread.CurrentThread.CurrentCulture = Culture;
- Thread.CurrentThread.CurrentUICulture = UICulture;
+ /// <summary>
+ /// Gets the culture.
+ /// </summary>
+ public CultureInfo Culture { get { return culture.Value; } }
- CultureInfo.CurrentCulture.ClearCachedData();
- CultureInfo.CurrentUICulture.ClearCachedData();
- }
+ /// <summary>
+ /// Gets the UI culture.
+ /// </summary>
+ public CultureInfo UICulture { get { return uiCulture.Value; } }
- /// <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;
+ /// <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();
+ CultureInfo.CurrentCulture.ClearCachedData();
+ CultureInfo.CurrentUICulture.ClearCachedData();
+ }
}
}