From ac769e656b122ff569c3f1534701b71e00fed586 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 27 Oct 2020 19:21:35 +0800 Subject: Split front and back end. --- Timeline.Tests/ErrorCodeTest.cs | 53 - Timeline.Tests/GlobalSuppressions.cs | 16 - .../Helpers/AsyncFunctionAssertionsExtensions.cs | 16 - Timeline.Tests/Helpers/CacheTestHelper.cs | 64 - Timeline.Tests/Helpers/HttpClientExtensions.cs | 51 - Timeline.Tests/Helpers/HttpResponseExtensions.cs | 35 - Timeline.Tests/Helpers/ImageHelper.cs | 26 - Timeline.Tests/Helpers/ParameterInfoAssertions.cs | 60 - Timeline.Tests/Helpers/ReflectionHelper.cs | 13 - Timeline.Tests/Helpers/ResponseAssertions.cs | 172 -- Timeline.Tests/Helpers/TestApplication.cs | 72 - Timeline.Tests/Helpers/TestClock.cs | 43 - Timeline.Tests/Helpers/TestDatabase.cs | 76 - .../IntegratedTests/AuthorizationTest.cs | 52 - Timeline.Tests/IntegratedTests/FrontEndTest.cs | 29 - .../IntegratedTests/IntegratedTestBase.cs | 164 -- Timeline.Tests/IntegratedTests/TimelineTest.cs | 1523 --------------- Timeline.Tests/IntegratedTests/TokenTest.cs | 165 -- .../IntegratedTests/UnknownEndpointTest.cs | 21 - Timeline.Tests/IntegratedTests/UserAvatarTest.cs | 251 --- Timeline.Tests/IntegratedTests/UserTest.cs | 447 ----- Timeline.Tests/PasswordGenerator.cs | 23 - Timeline.Tests/Properties/launchSettings.json | 2 - Timeline.Tests/Services/TimelineServiceTest.cs | 329 ---- Timeline.Tests/Timeline.Tests.csproj | 34 - Timeline.Tests/UsernameValidatorUnitTest.cs | 78 - Timeline.Tests/coverletArgs.runsettings | 13 - Timeline.Tests/packages.lock.json | 2040 -------------------- 28 files changed, 5868 deletions(-) delete mode 100644 Timeline.Tests/ErrorCodeTest.cs delete mode 100644 Timeline.Tests/GlobalSuppressions.cs delete mode 100644 Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs delete mode 100644 Timeline.Tests/Helpers/CacheTestHelper.cs delete mode 100644 Timeline.Tests/Helpers/HttpClientExtensions.cs delete mode 100644 Timeline.Tests/Helpers/HttpResponseExtensions.cs delete mode 100644 Timeline.Tests/Helpers/ImageHelper.cs delete mode 100644 Timeline.Tests/Helpers/ParameterInfoAssertions.cs delete mode 100644 Timeline.Tests/Helpers/ReflectionHelper.cs delete mode 100644 Timeline.Tests/Helpers/ResponseAssertions.cs delete mode 100644 Timeline.Tests/Helpers/TestApplication.cs delete mode 100644 Timeline.Tests/Helpers/TestClock.cs delete mode 100644 Timeline.Tests/Helpers/TestDatabase.cs delete mode 100644 Timeline.Tests/IntegratedTests/AuthorizationTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/FrontEndTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/IntegratedTestBase.cs delete mode 100644 Timeline.Tests/IntegratedTests/TimelineTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/TokenTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/UserAvatarTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/UserTest.cs delete mode 100644 Timeline.Tests/PasswordGenerator.cs delete mode 100644 Timeline.Tests/Properties/launchSettings.json delete mode 100644 Timeline.Tests/Services/TimelineServiceTest.cs delete mode 100644 Timeline.Tests/Timeline.Tests.csproj delete mode 100644 Timeline.Tests/UsernameValidatorUnitTest.cs delete mode 100644 Timeline.Tests/coverletArgs.runsettings delete mode 100644 Timeline.Tests/packages.lock.json (limited to 'Timeline.Tests') diff --git a/Timeline.Tests/ErrorCodeTest.cs b/Timeline.Tests/ErrorCodeTest.cs deleted file mode 100644 index 258ebf4e..00000000 --- a/Timeline.Tests/ErrorCodeTest.cs +++ /dev/null @@ -1,53 +0,0 @@ -using FluentAssertions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Timeline.Models.Http; -using Xunit; -using Xunit.Abstractions; - -namespace Timeline.Tests -{ - public class ErrorCodeTest - { - private readonly ITestOutputHelper _output; - - public ErrorCodeTest(ITestOutputHelper output) - { - _output = output; - } - - [Fact] - public void ShouldWork() - { - var errorCodes = new Dictionary(); - - void RecursiveCheckErrorCode(Type type) - { - foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy) - .Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(int))) - { - var name = type.FullName + "." + field.Name; - var value = (int)field.GetRawConstantValue(); - _output.WriteLine($"Find error code {name} , value is {value}."); - - value.Should().BeInRange(1000_0000, 9999_9999, "Error code should have exactly 8 digits."); - - errorCodes.Should().NotContainKey(value, - "identical error codes are found and conflict paths are {0} and {1}", - name, errorCodes.GetValueOrDefault(value)); - - errorCodes.Add(value, name); - } - - foreach (var nestedType in type.GetNestedTypes()) - { - RecursiveCheckErrorCode(nestedType); - } - } - - RecursiveCheckErrorCode(typeof(ErrorCodes)); - } - } -} diff --git a/Timeline.Tests/GlobalSuppressions.cs b/Timeline.Tests/GlobalSuppressions.cs deleted file mode 100644 index 0f873033..00000000 --- a/Timeline.Tests/GlobalSuppressions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "This is not a UI application.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Tests name have underscores.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Test may catch all exceptions.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "Test classes can be nested.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "This is redundant.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Test classes do not need to implement it that way.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Test classes do not need to implement it that way.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2234:Pass system uri objects instead of strings", Justification = "I really don't understand this rule.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "Tests do not need make strings resources.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1054:Uri parameters should not be strings", Justification = "That's unnecessary.")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1056:Uri properties should not be strings", Justification = "That's unnecessary.")] diff --git a/Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs b/Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs deleted file mode 100644 index b78309c0..00000000 --- a/Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using FluentAssertions; -using FluentAssertions.Primitives; -using FluentAssertions.Specialized; -using System; -using System.Threading.Tasks; - -namespace Timeline.Tests.Helpers -{ - public static class AsyncFunctionAssertionsExtensions - { - public static async Task> ThrowAsync(this AsyncFunctionAssertions assertions, Type exceptionType, string because = "", params object[] becauseArgs) - { - return (await assertions.ThrowAsync(because, becauseArgs)).Which.Should().BeAssignableTo(exceptionType); - } - } -} diff --git a/Timeline.Tests/Helpers/CacheTestHelper.cs b/Timeline.Tests/Helpers/CacheTestHelper.cs deleted file mode 100644 index b3709a28..00000000 --- a/Timeline.Tests/Helpers/CacheTestHelper.cs +++ /dev/null @@ -1,64 +0,0 @@ -using FluentAssertions; -using System; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Timeline.Models.Http; - -namespace Timeline.Tests.Helpers -{ - public static class CacheTestHelper - { - public static async Task TestCache(HttpClient client, string getUrl) - { - EntityTagHeaderValue eTag; - { - var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200); - var cacheControlHeader = res.Headers.CacheControl; - cacheControlHeader.NoCache.Should().BeTrue(); - cacheControlHeader.NoStore.Should().BeFalse(); - cacheControlHeader.Private.Should().BeTrue(); - cacheControlHeader.Public.Should().BeFalse(); - cacheControlHeader.MustRevalidate.Should().BeTrue(); - cacheControlHeader.MaxAge.Should().NotBeNull().And.Be(TimeSpan.FromDays(14)); - eTag = res.Headers.ETag; - } - - { - using var request = new HttpRequestMessage() - { - RequestUri = new Uri(client.BaseAddress, getUrl), - Method = HttpMethod.Get, - }; - request.Headers.TryAddWithoutValidation("If-None-Match", "\"dsdfd"); - var res = await client.SendAsync(request); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody(ErrorCodes.Common.Header.IfNonMatch_BadFormat); - } - - { - using var request = new HttpRequestMessage() - { - RequestUri = new Uri(client.BaseAddress, getUrl), - Method = HttpMethod.Get, - }; - request.Headers.TryAddWithoutValidation("If-None-Match", "\"aaa\""); - var res = await client.SendAsync(request); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - using var request = new HttpRequestMessage() - { - RequestUri = new Uri(client.BaseAddress, getUrl), - Method = HttpMethod.Get, - }; - request.Headers.Add("If-None-Match", eTag.ToString()); - var res = await client.SendAsync(request); - res.Should().HaveStatusCode(HttpStatusCode.NotModified); - } - } - } -} diff --git a/Timeline.Tests/Helpers/HttpClientExtensions.cs b/Timeline.Tests/Helpers/HttpClientExtensions.cs deleted file mode 100644 index 6513bbe7..00000000 --- a/Timeline.Tests/Helpers/HttpClientExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Mime; -using System.Text; -using System.Threading.Tasks; - -namespace Timeline.Tests.Helpers -{ - public static class HttpClientExtensions - { - public static Task PatchAsJsonAsync(this HttpClient client, string url, T body) - { - return client.PatchAsJsonAsync(new Uri(url, UriKind.RelativeOrAbsolute), body); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] - public static Task PatchAsJsonAsync(this HttpClient client, Uri url, T body) - { - return client.PatchAsync(url, new StringContent( - JsonConvert.SerializeObject(body), Encoding.UTF8, MediaTypeNames.Application.Json)); - } - - public static Task PutByteArrayAsync(this HttpClient client, string url, byte[] body, string mimeType) - { - return client.PutByteArrayAsync(new Uri(url, UriKind.RelativeOrAbsolute), body, mimeType); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] - public static Task PutByteArrayAsync(this HttpClient client, Uri url, byte[] body, string mimeType) - { - var content = new ByteArrayContent(body); - content.Headers.ContentLength = body.Length; - content.Headers.ContentType = new MediaTypeHeaderValue(mimeType); - return client.PutAsync(url, content); - } - - public static Task PutStringAsync(this HttpClient client, string url, string body, string mimeType = null) - { - return client.PutStringAsync(new Uri(url, UriKind.RelativeOrAbsolute), body, mimeType); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] - public static Task PutStringAsync(this HttpClient client, Uri url, string body, string mimeType = null) - { - var content = new StringContent(body, Encoding.UTF8, mimeType ?? MediaTypeNames.Text.Plain); - return client.PutAsync(url, content); - } - } -} diff --git a/Timeline.Tests/Helpers/HttpResponseExtensions.cs b/Timeline.Tests/Helpers/HttpResponseExtensions.cs deleted file mode 100644 index 2bd497f1..00000000 --- a/Timeline.Tests/Helpers/HttpResponseExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Net.Http; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Timeline.Models.Converters; -using Timeline.Models.Http; - -namespace Timeline.Tests.Helpers -{ - public static class HttpResponseExtensions - { - public static JsonSerializerOptions JsonSerializerOptions { get; } - - static HttpResponseExtensions() - { - JsonSerializerOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); - JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter()); - } - - public static async Task ReadBodyAsJsonAsync(this HttpResponseMessage response) - { - var stream = await response.Content.ReadAsStreamAsync(); - return await JsonSerializer.DeserializeAsync(stream, JsonSerializerOptions); - } - - public static Task ReadBodyAsCommonResponseAsync(this HttpResponseMessage response) - { - return response.ReadBodyAsJsonAsync(); - } - } -} diff --git a/Timeline.Tests/Helpers/ImageHelper.cs b/Timeline.Tests/Helpers/ImageHelper.cs deleted file mode 100644 index 9bed0917..00000000 --- a/Timeline.Tests/Helpers/ImageHelper.cs +++ /dev/null @@ -1,26 +0,0 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.PixelFormats; -using System.IO; - -namespace Timeline.Tests.Helpers -{ - public static class ImageHelper - { - public static byte[] CreatePngWithSize(int width, int height) - { - using var image = new Image(width, height); - using var stream = new MemoryStream(); - image.SaveAsPng(stream); - return stream.ToArray(); - } - - public static byte[] CreateImageWithSize(int width, int height, IImageFormat format) - { - using var image = new Image(width, height); - using var stream = new MemoryStream(); - image.Save(stream, format); - return stream.ToArray(); - } - } -} diff --git a/Timeline.Tests/Helpers/ParameterInfoAssertions.cs b/Timeline.Tests/Helpers/ParameterInfoAssertions.cs deleted file mode 100644 index d3e5a41e..00000000 --- a/Timeline.Tests/Helpers/ParameterInfoAssertions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using FluentAssertions; -using FluentAssertions.Execution; -using FluentAssertions.Formatting; -using FluentAssertions.Primitives; -using System; -using System.Reflection; - -namespace Timeline.Tests.Helpers -{ - public class ParameterInfoValueFormatter : IValueFormatter - { - public bool CanHandle(object value) - { - return value is ParameterInfo; - } - - public string Format(object value, FormattingContext context, FormatChild formatChild) - { - var param = (ParameterInfo)value; - return $"{param.Member.DeclaringType.FullName}.{param.Member.Name}#{param.Name}"; - } - } - - public class ParameterInfoAssertions : ReferenceTypeAssertions - { - static ParameterInfoAssertions() - { - Formatter.AddFormatter(new ParameterInfoValueFormatter()); - } - - public ParameterInfoAssertions(ParameterInfo parameterInfo) - { - Subject = parameterInfo; - } - - protected override string Identifier => "parameter"; - - public AndWhichConstraint BeDecoratedWith(string because = "", params object[] becauseArgs) - where TAttribute : Attribute - { - var attribute = Subject.GetCustomAttribute(false); - - Execute.Assertion - .BecauseOf(because, becauseArgs) - .ForCondition(attribute != null) - .FailWith("Expected {0} {1} to be decorated with {2}{reason}, but that attribute was not found.", - Identifier, Subject, typeof(TAttribute).FullName); - - return new AndWhichConstraint(this, attribute); - } - } - - public static class ParameterInfoAssertionExtensions - { - public static ParameterInfoAssertions Should(this ParameterInfo parameterInfo) - { - return new ParameterInfoAssertions(parameterInfo); - } - } -} diff --git a/Timeline.Tests/Helpers/ReflectionHelper.cs b/Timeline.Tests/Helpers/ReflectionHelper.cs deleted file mode 100644 index 3f6036e3..00000000 --- a/Timeline.Tests/Helpers/ReflectionHelper.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Linq; -using System.Reflection; - -namespace Timeline.Tests.Helpers -{ - public static class ReflectionHelper - { - public static ParameterInfo GetParameter(this MethodInfo methodInfo, string name) - { - return methodInfo.GetParameters().Where(p => p.Name == name).Single(); - } - } -} diff --git a/Timeline.Tests/Helpers/ResponseAssertions.cs b/Timeline.Tests/Helpers/ResponseAssertions.cs deleted file mode 100644 index 024732f5..00000000 --- a/Timeline.Tests/Helpers/ResponseAssertions.cs +++ /dev/null @@ -1,172 +0,0 @@ -using FluentAssertions; -using FluentAssertions.Execution; -using FluentAssertions.Formatting; -using FluentAssertions.Primitives; -using System; -using System.Globalization; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Text.Json.Serialization; -using Timeline.Models.Converters; -using Timeline.Models.Http; - -namespace Timeline.Tests.Helpers -{ - public class HttpResponseMessageValueFormatter : IValueFormatter - { - public bool CanHandle(object value) - { - return value is HttpResponseMessage; - } - - public string Format(object value, FormattingContext context, FormatChild formatChild) - { - string newline = context.UseLineBreaks ? Environment.NewLine : ""; - string padding = new string('\t', context.Depth); - - var res = (HttpResponseMessage)value; - - var builder = new StringBuilder(); - builder.Append($"{newline}{padding} Status Code: {res.StatusCode} ; Body: "); - - try - { - var task = res.Content.ReadAsStringAsync(); - task.Wait(); - var body = task.Result; - if (body.Length > 40) - { - body = body[0..40] + " ..."; - } - builder.Append(body); - } - catch (AggregateException) - { - builder.Append("NOT A STRING."); - } - - return builder.ToString(); - } - } - - public class HttpResponseMessageAssertions - : ReferenceTypeAssertions - { - static HttpResponseMessageAssertions() - { - Formatter.AddFormatter(new HttpResponseMessageValueFormatter()); - } - - public HttpResponseMessageAssertions(HttpResponseMessage instance) - { - Subject = instance; - } - - protected override string Identifier => "HttpResponseMessage"; - - public AndConstraint HaveStatusCode(int expected, string because = "", params object[] becauseArgs) - { - return HaveStatusCode((HttpStatusCode)expected, because, becauseArgs); - } - - public AndConstraint HaveStatusCode(HttpStatusCode expected, string because = "", params object[] becauseArgs) - { - Execute.Assertion.BecauseOf(because, becauseArgs) - .ForCondition(Subject.StatusCode == expected) - .FailWith("Expected status code of {context:HttpResponseMessage} to be {0}{reason}, but found {1}.", expected, Subject.StatusCode); - return new AndConstraint(this); - } - - public AndWhichConstraint HaveJsonBody(string because = "", params object[] becauseArgs) - { - var a = Execute.Assertion.BecauseOf(because, becauseArgs); - string body; - try - { - var task = Subject.Content.ReadAsStringAsync(); - task.Wait(); - body = task.Result; - } - catch (AggregateException e) - { - a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string{reason}, but failed to read it or it was not a string. Exception is {0}.", e.InnerExceptions); - return new AndWhichConstraint(this, null); - } - - - try - { - var options = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - options.Converters.Add(new JsonStringEnumConverter()); - options.Converters.Add(new JsonDateTimeConverter()); - - var result = JsonSerializer.Deserialize(body, options); - - return new AndWhichConstraint(this, result); - } - catch (JsonException e) - { - a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string{reason}, but failed to deserialize it. Exception is {0}.", e); - return new AndWhichConstraint(this, null); - } - } - } - - public static class AssertionResponseExtensions - { - public static HttpResponseMessageAssertions Should(this HttpResponseMessage instance) - { - return new HttpResponseMessageAssertions(instance); - } - - public static AndWhichConstraint HaveCommonBody(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveJsonBody(because, becauseArgs); - } - - public static void HaveCommonBody(this HttpResponseMessageAssertions assertions, int code, string message = null, params object[] messageArgs) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + string.Format(CultureInfo.CurrentCulture, message, messageArgs); - var body = assertions.HaveCommonBody("Response body should be CommonResponse{0}", message).Which; - body.Code.Should().Be(code, "Response body code is not the specified one{0}", message); - } - - public static AndWhichConstraint> HaveCommonDataBody(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveJsonBody>(because, becauseArgs); - } - - public static void BePut(this HttpResponseMessageAssertions assertions, bool create, string because = "", params object[] becauseArgs) - { - var body = assertions.HaveStatusCode(create ? 201 : 200, because, becauseArgs) - .And.HaveJsonBody(because, becauseArgs) - .Which; - body.Code.Should().Be(0); - body.Data.Create.Should().Be(create); - } - - public static void BeDelete(this HttpResponseMessageAssertions assertions, bool delete, string because = "", params object[] becauseArgs) - { - var body = assertions.HaveStatusCode(200, because, becauseArgs) - .And.HaveJsonBody(because, becauseArgs) - .Which; - body.Code.Should().Be(0); - body.Data.Delete.Should().Be(delete); - } - - public static void BeInvalidModel(this HttpResponseMessageAssertions assertions, string message = null) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + message; - assertions.HaveStatusCode(400, "Invalid Model Error must have 400 status code{0}", message) - .And.HaveCommonBody("Invalid Model Error must have CommonResponse body{0}", message) - .Which.Code.Should().Be(ErrorCodes.Common.InvalidModel, - "Invalid Model Error must have code {0} in body{1}", - ErrorCodes.Common.InvalidModel, message); - } - } -} diff --git a/Timeline.Tests/Helpers/TestApplication.cs b/Timeline.Tests/Helpers/TestApplication.cs deleted file mode 100644 index 684ffe2c..00000000 --- a/Timeline.Tests/Helpers/TestApplication.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using Timeline.Configs; -using Timeline.Entities; -using Xunit; - -namespace Timeline.Tests.Helpers -{ - public class TestApplication : IAsyncLifetime - { - public TestDatabase Database { get; } - - public IHost Host { get; private set; } - - public string WorkDir { get; private set; } - - public TestApplication() - { - Database = new TestDatabase(false); - } - - public async Task InitializeAsync() - { - await Database.InitializeAsync(); - - WorkDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - Directory.CreateDirectory(WorkDir); - - Host = await Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() - .ConfigureAppConfiguration((context, config) => - { - config.AddInMemoryCollection(new Dictionary - { - [ApplicationConfiguration.UseMockFrontEndKey] = "true", - ["WorkDir"] = WorkDir - }); - }) - .ConfigureServices(services => - { - services.AddDbContext(options => - { - options.UseSqlite(Database.Connection); - }); - }) - .ConfigureWebHost(webBuilder => - { - webBuilder - .UseTestServer() - .UseStartup(); - }) - .StartAsync(); - } - - public async Task DisposeAsync() - { - await Host.StopAsync(); - Host.Dispose(); - - Directory.Delete(WorkDir, true); - - await Database.DisposeAsync(); - } - } -} diff --git a/Timeline.Tests/Helpers/TestClock.cs b/Timeline.Tests/Helpers/TestClock.cs deleted file mode 100644 index 34adb245..00000000 --- a/Timeline.Tests/Helpers/TestClock.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Timeline.Services; - -namespace Timeline.Tests.Helpers -{ - public class TestClock : IClock - { - private DateTime? _currentTime; - - public DateTime GetCurrentTime() - { - return _currentTime ?? DateTime.UtcNow; - } - - public void SetCurrentTime(DateTime? mockTime) - { - _currentTime = mockTime; - } - - public DateTime SetMockCurrentTime() - { - var time = new DateTime(3000, 1, 1, 1, 1, 1, DateTimeKind.Utc); - _currentTime = time; - return time; - } - - public DateTime ForwardCurrentTime() - { - return ForwardCurrentTime(TimeSpan.FromDays(1)); - } - - public DateTime ForwardCurrentTime(TimeSpan timeSpan) - { - if (_currentTime == null) - return SetMockCurrentTime(); - _currentTime += timeSpan; - return _currentTime.Value; - } - } -} diff --git a/Timeline.Tests/Helpers/TestDatabase.cs b/Timeline.Tests/Helpers/TestDatabase.cs deleted file mode 100644 index f0c26180..00000000 --- a/Timeline.Tests/Helpers/TestDatabase.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Migrations; -using Timeline.Models; -using Timeline.Services; -using Xunit; - -namespace Timeline.Tests.Helpers -{ - public class TestDatabase : IAsyncLifetime - { - private readonly bool _createUser; - - public TestDatabase(bool createUser = true) - { - _createUser = createUser; - Connection = new SqliteConnection("Data Source=:memory:;"); - } - - public async Task InitializeAsync() - { - await Connection.OpenAsync(); - - using (var context = CreateContext()) - { - await context.Database.EnsureCreatedAsync(); - context.JwtToken.Add(new JwtTokenEntity - { - Key = JwtTokenGenerateHelper.GenerateKey() - }); - await context.SaveChangesAsync(); - - if (_createUser) - { - var passwordService = new PasswordService(); - var userService = new UserService(NullLogger.Instance, context, passwordService, new Clock()); - - await userService.CreateUser(new User - { - Username = "admin", - Password = "adminpw", - Administrator = true, - Nickname = "administrator" - }); - - await userService.CreateUser(new User - { - Username = "user", - Password = "userpw", - Administrator = false, - Nickname = "imuser" - }); - } - } - } - - public async Task DisposeAsync() - { - await Connection.CloseAsync(); - await Connection.DisposeAsync(); - } - - public SqliteConnection Connection { get; } - - public DatabaseContext CreateContext() - { - var options = new DbContextOptionsBuilder() - .UseSqlite(Connection).Options; - - return new DatabaseContext(options); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/AuthorizationTest.cs b/Timeline.Tests/IntegratedTests/AuthorizationTest.cs deleted file mode 100644 index 38071394..00000000 --- a/Timeline.Tests/IntegratedTests/AuthorizationTest.cs +++ /dev/null @@ -1,52 +0,0 @@ -using FluentAssertions; -using System.Net; -using System.Threading.Tasks; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class AuthorizationTest : IntegratedTestBase - { - private const string BaseUrl = "testing/auth/"; - private const string AuthorizeUrl = BaseUrl + "Authorize"; - private const string UserUrl = BaseUrl + "User"; - private const string AdminUrl = BaseUrl + "Admin"; - - [Fact] - public async Task UnauthenticationTest() - { - using var client = await CreateDefaultClient(); - var response = await client.GetAsync(AuthorizeUrl); - response.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - [Fact] - public async Task AuthenticationTest() - { - using var client = await CreateClientAsUser(); - var response = await client.GetAsync(AuthorizeUrl); - response.Should().HaveStatusCode(HttpStatusCode.OK); - } - - [Fact] - public async Task UserAuthorizationTest() - { - using var client = await CreateClientAsUser(); - var response1 = await client.GetAsync(UserUrl); - response1.Should().HaveStatusCode(HttpStatusCode.OK); - var response2 = await client.GetAsync(AdminUrl); - response2.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task AdminAuthorizationTest() - { - using var client = await CreateClientAsAdministrator(); - var response1 = await client.GetAsync(UserUrl); - response1.Should().HaveStatusCode(HttpStatusCode.OK); - var response2 = await client.GetAsync(AdminUrl); - response2.Should().HaveStatusCode(HttpStatusCode.OK); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/FrontEndTest.cs b/Timeline.Tests/IntegratedTests/FrontEndTest.cs deleted file mode 100644 index 39a6e545..00000000 --- a/Timeline.Tests/IntegratedTests/FrontEndTest.cs +++ /dev/null @@ -1,29 +0,0 @@ -using FluentAssertions; -using System.Net.Mime; -using System.Threading.Tasks; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class FrontEndTest : IntegratedTestBase - { - [Fact] - public async Task Index() - { - using var client = await CreateDefaultClient(false); - var res = await client.GetAsync("index.html"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be(MediaTypeNames.Text.Html); - } - - [Fact] - public async Task Fallback() - { - using var client = await CreateDefaultClient(false); - var res = await client.GetAsync("aaaaaaaaaaaaaaa"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be(MediaTypeNames.Text.Html); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs b/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs deleted file mode 100644 index 7cf27297..00000000 --- a/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs +++ /dev/null @@ -1,164 +0,0 @@ -using FluentAssertions; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Timeline.Models; -using Timeline.Models.Converters; -using Timeline.Models.Http; -using Timeline.Services; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public abstract class IntegratedTestBase : IAsyncLifetime - { - protected TestApplication TestApp { get; } - - public IReadOnlyList UserInfos { get; private set; } - - private readonly int _userCount; - - public IntegratedTestBase() : this(1) - { - - } - - public IntegratedTestBase(int userCount) - { - if (userCount < 0) - throw new ArgumentOutOfRangeException(nameof(userCount), userCount, "User count can't be negative."); - - _userCount = userCount; - - TestApp = new TestApplication(); - } - - protected virtual Task OnInitializeAsync() - { - return Task.CompletedTask; - } - - protected virtual Task OnDisposeAsync() - { - return Task.CompletedTask; - } - - protected virtual void OnDispose() - { - - } - - public async Task InitializeAsync() - { - await TestApp.InitializeAsync(); - - using (var scope = TestApp.Host.Services.CreateScope()) - { - var users = new List() - { - new User - { - Username = "admin", - Password = "adminpw", - Administrator = true, - Nickname = "administrator" - } - }; - - for (int i = 1; i <= _userCount; i++) - { - users.Add(new User - { - Username = $"user{i}", - Password = $"user{i}pw", - Administrator = false, - Nickname = $"imuser{i}" - }); - } - - var userInfoList = new List(); - - var userService = scope.ServiceProvider.GetRequiredService(); - foreach (var user in users) - { - await userService.CreateUser(user); - } - - using var client = await CreateDefaultClient(); - var options = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - options.Converters.Add(new JsonStringEnumConverter()); - options.Converters.Add(new JsonDateTimeConverter()); - foreach (var user in users) - { - var s = await client.GetStringAsync($"users/{user.Username}"); - userInfoList.Add(JsonSerializer.Deserialize(s, options)); - } - - UserInfos = userInfoList; - } - - await OnInitializeAsync(); - } - - public async Task DisposeAsync() - { - await OnDisposeAsync(); - OnDispose(); - await TestApp.DisposeAsync(); - } - - public Task CreateDefaultClient(bool setApiBase = true) - { - var client = TestApp.Host.GetTestServer().CreateClient(); - if (setApiBase) - { - client.BaseAddress = new Uri(client.BaseAddress, "api/"); - } - return Task.FromResult(client); - } - - public async Task CreateClientWithCredential(string username, string password, bool setApiBase = true) - { - var client = TestApp.Host.GetTestServer().CreateClient(); - if (setApiBase) - { - client.BaseAddress = new Uri(client.BaseAddress, "api/"); - } - var response = await client.PostAsJsonAsync("token/create", - new CreateTokenRequest { Username = username, Password = password }); - var token = response.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Token; - client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); - return client; - } - - public Task CreateClientAs(int userNumber, bool setApiBase = true) - { - if (userNumber < 0) - return CreateDefaultClient(setApiBase); - if (userNumber == 0) - return CreateClientWithCredential("admin", "adminpw", setApiBase); - else - return CreateClientWithCredential($"user{userNumber}", $"user{userNumber}pw", setApiBase); - } - - public Task CreateClientAsAdministrator(bool setApiBase = true) - { - return CreateClientAs(0, setApiBase); - } - - public Task CreateClientAsUser(bool setApiBase = true) - { - return CreateClientAs(1, setApiBase); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/TimelineTest.cs b/Timeline.Tests/IntegratedTests/TimelineTest.cs deleted file mode 100644 index ec46b96a..00000000 --- a/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ /dev/null @@ -1,1523 +0,0 @@ -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Models; -using Timeline.Models.Http; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public static class TimelineHelper - { - public static TimelinePostContentInfo TextPostContent(string text) - { - return new TimelinePostContentInfo - { - Type = "text", - Text = text - }; - } - - public static TimelinePostCreateRequest TextPostCreateRequest(string text, DateTime? time = null) - { - return new TimelinePostCreateRequest - { - Content = new TimelinePostCreateRequestContent - { - Type = "text", - Text = text - }, - Time = time - }; - } - } - - public class TimelineTest : IntegratedTestBase - { - public TimelineTest() : base(3) - { - } - - protected override async Task OnInitializeAsync() - { - await CreateTestTimelines(); - } - - private List _testTimelines; - - private async Task CreateTestTimelines() - { - _testTimelines = new List(); - for (int i = 0; i <= 3; i++) - { - var client = await CreateClientAs(i); - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = $"t{i}" }); - var timelineInfo = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - _testTimelines.Add(timelineInfo); - } - } - - private static string CalculateUrlTail(string subpath, ICollection> query) - { - StringBuilder result = new StringBuilder(); - if (subpath != null) - { - if (!subpath.StartsWith("/", StringComparison.OrdinalIgnoreCase)) - result.Append('/'); - result.Append(subpath); - } - - if (query != null && query.Count != 0) - { - result.Append('?'); - foreach (var (key, value, index) in query.Select((pair, index) => (pair.Key, pair.Value, index))) - { - result.Append(WebUtility.UrlEncode(key)); - result.Append('='); - result.Append(WebUtility.UrlEncode(value)); - if (index != query.Count - 1) - result.Append('&'); - } - } - - return result.ToString(); - } - - private static string GeneratePersonalTimelineUrl(int id, string subpath = null, ICollection> query = null) - { - return $"timelines/@{(id == 0 ? "admin" : ("user" + id))}{CalculateUrlTail(subpath, query)}"; - } - - private static string GenerateOrdinaryTimelineUrl(int id, string subpath = null, ICollection> query = null) - { - return $"timelines/t{id}{CalculateUrlTail(subpath, query)}"; - } - - public delegate string TimelineUrlGenerator(int userId, string subpath = null, ICollection> query = null); - - public static IEnumerable TimelineUrlGeneratorData() - { - yield return new[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl) }; - yield return new[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl) }; - } - - private static string GeneratePersonalTimelineUrlByName(string name, string subpath = null) - { - return $"timelines/@{name}{(subpath == null ? "" : "/" + subpath)}"; - } - - private static string GenerateOrdinaryTimelineUrlByName(string name, string subpath = null) - { - return $"timelines/{name}{(subpath == null ? "" : "/" + subpath)}"; - } - - public static IEnumerable TimelineUrlByNameGeneratorData() - { - yield return new[] { new Func(GeneratePersonalTimelineUrlByName) }; - yield return new[] { new Func(GenerateOrdinaryTimelineUrlByName) }; - } - - [Fact] - public async Task TimelineGet_Should_Work() - { - using var client = await CreateDefaultClient(); - { - var res = await client.GetAsync("timelines/@user1"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Owner.Should().BeEquivalentTo(UserInfos[1]); - body.Visibility.Should().Be(TimelineVisibility.Register); - body.Description.Should().Be(""); - body.Members.Should().NotBeNull().And.BeEmpty(); - var links = body._links; - links.Should().NotBeNull(); - links.Self.Should().EndWith("timelines/@user1"); - links.Posts.Should().EndWith("timelines/@user1/posts"); - } - - { - var res = await client.GetAsync("timelines/t1"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Owner.Should().BeEquivalentTo(UserInfos[1]); - body.Visibility.Should().Be(TimelineVisibility.Register); - body.Description.Should().Be(""); - body.Members.Should().NotBeNull().And.BeEmpty(); - var links = body._links; - links.Should().NotBeNull(); - links.Self.Should().EndWith("timelines/t1"); - links.Posts.Should().EndWith("timelines/t1/posts"); - } - } - - [Fact] - public async Task TimelineList() - { - TimelineInfo user1Timeline; - - var client = await CreateDefaultClient(); - - { - var res = await client.GetAsync("timelines/@user1"); - user1Timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - } - - { - var testResult = new List(); - testResult.Add(user1Timeline); - testResult.AddRange(_testTimelines); - - var res = await client.GetAsync("timelines"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which.Should().BeEquivalentTo(testResult); - } - } - - [Fact] - public async Task TimelineList_WithQuery() - { - var testResultRelate = new List(); - var testResultOwn = new List(); - var testResultJoin = new List(); - var testResultOwnPrivate = new List(); - var testResultRelatePublic = new List(); - var testResultRelateRegister = new List(); - var testResultJoinPrivate = new List(); - var testResultPublic = new List(); - - { - var client = await CreateClientAsUser(); - - { - var res = await client.PutAsync("timelines/@user1/members/user3", null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PutAsync("timelines/t1/members/user3", null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PatchAsJsonAsync("timelines/@user1", new TimelinePatchRequest { Visibility = TimelineVisibility.Public }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PatchAsJsonAsync("timelines/t1", new TimelinePatchRequest { Visibility = TimelineVisibility.Register }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.GetAsync("timelines/@user1"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - testResultRelate.Add(timeline); - testResultJoin.Add(timeline); - testResultRelatePublic.Add(timeline); - testResultPublic.Add(timeline); - } - - { - var res = await client.GetAsync("timelines/t1"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - testResultRelate.Add(timeline); - testResultJoin.Add(timeline); - testResultRelateRegister.Add(timeline); - } - } - - { - var client = await CreateClientAs(2); - - { - var res = await client.PutAsync("timelines/@user2/members/user3", null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PutAsync("timelines/t2/members/user3", null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PatchAsJsonAsync("timelines/@user2", new TimelinePatchRequest { Visibility = TimelineVisibility.Register }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PatchAsJsonAsync("timelines/t2", new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.GetAsync("timelines/@user2"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - testResultRelate.Add(timeline); - testResultJoin.Add(timeline); - testResultRelateRegister.Add(timeline); - } - - { - var res = await client.GetAsync("timelines/t2"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - testResultRelate.Add(timeline); - testResultJoin.Add(timeline); - testResultJoinPrivate.Add(timeline); - } - } - - { - var client = await CreateClientAs(3); - - { - var res = await client.PatchAsJsonAsync("timelines/@user3", new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PatchAsJsonAsync("timelines/t3", new TimelinePatchRequest { Visibility = TimelineVisibility.Register }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.GetAsync("timelines/@user3"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - testResultRelate.Add(timeline); - testResultOwn.Add(timeline); - testResultOwnPrivate.Add(timeline); - } - - { - var res = await client.GetAsync("timelines/t3"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - testResultRelate.Add(timeline); - testResultOwn.Add(timeline); - testResultRelateRegister.Add(timeline); - } - } - - { - var client = await CreateClientAs(3); - { - var res = await client.GetAsync("timelines?relate=user3"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultRelate); - } - - { - var res = await client.GetAsync("timelines?relate=user3&relateType=own"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultOwn); - } - - { - var res = await client.GetAsync("timelines?relate=user3&visibility=public"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultRelatePublic); - } - - { - var res = await client.GetAsync("timelines?relate=user3&visibility=register"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultRelateRegister); - } - - { - var res = await client.GetAsync("timelines?relate=user3&relateType=join&visibility=private"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultJoinPrivate); - } - - { - var res = await client.GetAsync("timelines?relate=user3&relateType=own&visibility=private"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultOwnPrivate); - } - } - - { - var client = await CreateDefaultClient(); - { - var res = await client.GetAsync("timelines?visibility=public"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultPublic); - } - } - } - - [Fact] - public async Task TimelineList_InvalidModel() - { - var client = await CreateClientAsUser(); - - { - var res = await client.GetAsync("timelines?relate=us!!"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.GetAsync("timelines?relateType=aaa"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.GetAsync("timelines?visibility=aaa"); - res.Should().BeInvalidModel(); - } - } - - [Fact] - public async Task TimelineCreate_Should_Work() - { - { - using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - using (var client = await CreateClientAsUser()) - { - { - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "!!!" }); - res.Should().BeInvalidModel(); - } - - TimelineInfo timelineInfo; - { - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - timelineInfo = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - } - - { - var res = await client.GetAsync("timelines/aaa"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timelineInfo); - } - - { - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.NameConflict); - } - } - } - - [Fact] - public async Task TimelineDelete_Should_Work() - { - { - using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - { - using var client = await CreateClientAs(2); - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - { - using var client = await CreateClientAsAdministrator(); - - { - var res = await client.DeleteAsync("timelines/!!!"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.DeleteAsync("timelines/t2"); - res.Should().BeDelete(true); - } - - { - var res = await client.DeleteAsync("timelines/t2"); - res.Should().BeDelete(false); - } - } - - { - using var client = await CreateClientAs(1); - - { - var res = await client.DeleteAsync("timelines/!!!"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.DeleteAsync("timelines/t1"); - res.Should().BeDelete(true); - } - - { - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(400); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlByNameGeneratorData))] - public async Task InvalidModel_BadName(Func generator) - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.GetAsync(generator("aaa!!!", null)); - res.Should().BeInvalidModel(); - } - { - var res = await client.PatchAsJsonAsync(generator("aaa!!!", null), new TimelinePatchRequest { }); - res.Should().BeInvalidModel(); - } - { - var res = await client.PutAsync(generator("aaa!!!", "members/user1"), null); - res.Should().BeInvalidModel(); - } - { - var res = await client.DeleteAsync(generator("aaa!!!", "members/user1")); - res.Should().BeInvalidModel(); - } - { - var res = await client.GetAsync(generator("aaa!!!", "posts")); - res.Should().BeInvalidModel(); - } - { - var res = await client.PostAsJsonAsync(generator("aaa!!!", "posts"), TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().BeInvalidModel(); - } - { - var res = await client.DeleteAsync(generator("aaa!!!", "posts/123")); - res.Should().BeInvalidModel(); - } - { - var res = await client.GetAsync(generator("aaa!!!", "posts/123/data")); - res.Should().BeInvalidModel(); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlByNameGeneratorData))] - public async Task Ordinary_NotFound(Func generator) - { - var errorCode = generator == GenerateOrdinaryTimelineUrlByName ? ErrorCodes.TimelineController.NotExist : ErrorCodes.UserCommon.NotExist; - - using var client = await CreateClientAsAdministrator(); - { - var res = await client.GetAsync(generator("notexist", null)); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); - } - { - var res = await client.PatchAsJsonAsync(generator("notexist", null), new TimelinePatchRequest { }); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.PutAsync(generator("notexist", "members/user1"), null); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.DeleteAsync(generator("notexist", "members/user1")); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.GetAsync(generator("notexist", "posts")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); - } - { - var res = await client.PostAsJsonAsync(generator("notexist", "posts"), TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.DeleteAsync(generator("notexist", "posts/123")); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.GetAsync(generator("notexist", "posts/123/data")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Description_Should_Work(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - async Task AssertDescription(string description) - { - var res = await client.GetAsync(generator(1, null)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Description.Should().Be(description); - } - - const string mockDescription = "haha"; - - await AssertDescription(""); - { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Description = mockDescription }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Description.Should().Be(mockDescription); - await AssertDescription(mockDescription); - } - { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Description = null }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Description.Should().Be(mockDescription); - await AssertDescription(mockDescription); - } - { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Description = "" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Description.Should().Be(""); - await AssertDescription(""); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Member_Should_Work(TimelineUrlGenerator generator) - { - var getUrl = generator(1, null); - using var client = await CreateClientAsUser(); - - async Task AssertMembers(IList members) - { - var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Members.Should().NotBeNull().And.BeEquivalentTo(members); - } - - async Task AssertEmptyMembers() - { - var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Members.Should().NotBeNull().And.BeEmpty(); - } - - await AssertEmptyMembers(); - { - var res = await client.PutAsync(generator(1, "members/usernotexist"), null); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.MemberPut_NotExist); - } - await AssertEmptyMembers(); - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - await AssertMembers(new List { UserInfos[2] }); - { - var res = await client.DeleteAsync(generator(1, "members/user2")); - res.Should().BeDelete(true); - } - await AssertEmptyMembers(); - { - var res = await client.DeleteAsync(generator(1, "members/aaa")); - res.Should().BeDelete(false); - } - await AssertEmptyMembers(); - } - - public static IEnumerable Permission_Timeline_Data() - { - yield return new object[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl), -1, 200, 401, 401, 401, 401 }; - yield return new object[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl), 1, 200, 200, 403, 200, 403 }; - yield return new object[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl), 0, 200, 200, 200, 200, 200 }; - yield return new object[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl), -1, 200, 401, 401, 401, 401 }; - yield return new object[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl), 1, 200, 200, 403, 200, 403 }; - yield return new object[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl), 0, 200, 200, 200, 200, 200 }; - } - - [Theory] - [MemberData(nameof(Permission_Timeline_Data))] - public async Task Permission_Timeline(TimelineUrlGenerator generator, int userNumber, int get, int opPatchUser, int opPatchAdmin, int opMemberUser, int opMemberAdmin) - { - using var client = await CreateClientAs(userNumber); - { - var res = await client.GetAsync("timelines/t1"); - res.Should().HaveStatusCode(get); - } - - { - var res = await client.PatchAsJsonAsync(generator(1, null), new TimelinePatchRequest { Description = "hahaha" }); - res.Should().HaveStatusCode(opPatchUser); - } - - { - var res = await client.PatchAsJsonAsync(generator(0, null), new TimelinePatchRequest { Description = "hahaha" }); - res.Should().HaveStatusCode(opPatchAdmin); - } - - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(opMemberUser); - } - - { - var res = await client.DeleteAsync(generator(1, "members/user2")); - res.Should().HaveStatusCode(opMemberUser); - } - - { - var res = await client.PutAsync(generator(0, "members/user2"), null); - res.Should().HaveStatusCode(opMemberAdmin); - } - - { - var res = await client.DeleteAsync(generator(0, "members/user2")); - res.Should().HaveStatusCode(opMemberAdmin); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Visibility_Test(TimelineUrlGenerator generator) - { - var userUrl = generator(1, "posts"); - var adminUrl = generator(0, "posts"); - { - - using var client = await CreateClientAsUser(); - using var content = new StringContent(@"{""visibility"":""abcdefg""}", System.Text.Encoding.UTF8, System.Net.Mime.MediaTypeNames.Application.Json); - var res = await client.PatchAsync(generator(1, null), content); - res.Should().BeInvalidModel(); - } - { // default visibility is registered - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(403); - } - - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(200); - } - } - - { // change visibility to public - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Visibility = TimelineVisibility.Public }); - res.Should().HaveStatusCode(200); - } - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(200); - } - } - - { // change visibility to private - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } - { - var res = await client.PatchAsJsonAsync(generator(0, null), - new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } - } - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(403); - } - { // user can't read admin's - using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(403); - } - { // admin can read user's - using var client = await CreateClientAsAdministrator(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(200); - } - { // add member - using var client = await CreateClientAsAdministrator(); - var res = await client.PutAsync(generator(0, "members/user1"), null); - res.Should().HaveStatusCode(200); - } - { // now user can read admin's - using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(200); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Permission_Post_Create(TimelineUrlGenerator generator) - { - using (var client = await CreateClientAsUser()) - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - - using (var client = await CreateDefaultClient()) - { - { // no auth should get 401 - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(401); - } - } - - using (var client = await CreateClientAsUser()) - { - { // post self's - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } - { // post other not as a member should get 403 - var res = await client.PostAsJsonAsync(generator(0, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(403); - } - } - - using (var client = await CreateClientAsAdministrator()) - { - { // post as admin - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } - } - - using (var client = await CreateClientAs(2)) - { - { // post as member - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Permission_Post_Delete(TimelineUrlGenerator generator) - { - async Task CreatePost(int userNumber) - { - using var client = await CreateClientAs(userNumber); - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - return res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Id; - } - - using (var client = await CreateClientAsUser()) - { - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - { - var res = await client.PutAsync(generator(1, "members/user3"), null); - res.Should().HaveStatusCode(200); - } - } - - { // no auth should get 401 - using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync(generator(1, "posts/12")); - res.Should().HaveStatusCode(401); - } - - { // self can delete self - var postId = await CreatePost(1); - using var client = await CreateClientAsUser(); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); - } - - { // admin can delete any - var postId = await CreatePost(1); - using var client = await CreateClientAsAdministrator(); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); - } - - { // owner can delete other - var postId = await CreatePost(2); - using var client = await CreateClientAsUser(); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); - } - - { // author can delete self - var postId = await CreatePost(2); - using var client = await CreateClientAs(2); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); - } - - { // otherwise is forbidden - var postId = await CreatePost(2); - using var client = await CreateClientAs(3); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(403); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task TextPost_ShouldWork(TimelineUrlGenerator generator) - { - { - using var client = await CreateClientAsUser(); - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEmpty(); - } - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest(null)); - res.Should().BeInvalidModel(); - } - const string mockContent = "aaa"; - TimelinePostInfo createRes; - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest(mockContent)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Should().NotBeNull(); - body.Content.Should().BeEquivalentTo(TimelineHelper.TextPostContent(mockContent)); - body.Author.Should().BeEquivalentTo(UserInfos[1]); - body.Deleted.Should().BeFalse(); - createRes = body; - } - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEquivalentTo(createRes); - } - const string mockContent2 = "bbb"; - var mockTime2 = DateTime.UtcNow.AddDays(-1); - TimelinePostInfo createRes2; - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest(mockContent2, mockTime2)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Should().NotBeNull(); - body.Content.Should().BeEquivalentTo(TimelineHelper.TextPostContent(mockContent2)); - body.Author.Should().BeEquivalentTo(UserInfos[1]); - body.Time.Should().BeCloseTo(mockTime2, 1000); - body.Deleted.Should().BeFalse(); - createRes2 = body; - } - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEquivalentTo(createRes, createRes2); - } - { - var res = await client.DeleteAsync(generator(1, $"posts/{createRes.Id}")); - res.Should().BeDelete(true); - } - { - var res = await client.DeleteAsync(generator(1, $"posts/{createRes.Id}")); - res.Should().BeDelete(false); - } - { - var res = await client.DeleteAsync(generator(1, "posts/30000")); - res.Should().BeDelete(false); - } - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEquivalentTo(createRes2); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task GetPost_Should_Ordered(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - async Task CreatePost(DateTime time) - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa", time)); - return res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Id; - } - - var now = DateTime.UtcNow; - var id0 = await CreatePost(now.AddDays(1)); - var id1 = await CreatePost(now.AddDays(-1)); - var id2 = await CreatePost(now); - - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Select(p => p.Id).Should().Equal(id1, id2, id0); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task CreatePost_InvalidModel(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = null }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = null } }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "hahaha" } }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "text", Text = null } }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = null } }); - res.Should().BeInvalidModel(); - } - - { - // image not base64 - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = "!!!" } }); - res.Should().BeInvalidModel(); - } - - { - // image base64 not image - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = Convert.ToBase64String(new byte[] { 0x01, 0x02, 0x03 }) } }); - res.Should().BeInvalidModel(); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task ImagePost_ShouldWork(TimelineUrlGenerator generator) - { - var imageData = ImageHelper.CreatePngWithSize(100, 200); - - long postId; - string postImageUrl; - - void AssertPostContent(TimelinePostContentInfo content) - { - content.Type.Should().Be(TimelinePostContentTypes.Image); - content.Url.Should().EndWith(generator(1, $"posts/{postId}/data")); - content.Text.Should().Be(null); - } - - using var client = await CreateClientAsUser(); - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - new TimelinePostCreateRequest - { - Content = new TimelinePostCreateRequestContent - { - Type = TimelinePostContentTypes.Image, - Data = Convert.ToBase64String(imageData) - } - }); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - postId = body.Id; - postImageUrl = body.Content.Url; - AssertPostContent(body.Content); - } - - { - var res = await client.GetAsync(generator(1, "posts")); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Should().HaveCount(1); - var post = body[0]; - post.Id.Should().Be(postId); - AssertPostContent(post.Content); - } - - { - var res = await client.GetAsync(generator(1, $"posts/{postId}/data")); - res.Content.Headers.ContentType.MediaType.Should().Be("image/png"); - var data = await res.Content.ReadAsByteArrayAsync(); - var image = Image.Load(data, out var format); - image.Width.Should().Be(100); - image.Height.Should().Be(200); - format.Name.Should().Be(PngFormat.Instance.Name); - } - - { - await CacheTestHelper.TestCache(client, generator(1, $"posts/{postId}/data")); - } - - { - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().BeDelete(true); - } - - { - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().BeDelete(false); - } - - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEmpty(); - } - - { - using var scope = TestApp.Host.Services.CreateScope(); - var database = scope.ServiceProvider.GetRequiredService(); - var count = await database.Data.CountAsync(); - count.Should().Be(0); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task ImagePost_400(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - { - var res = await client.GetAsync(generator(1, "posts/11234/data")); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody(ErrorCodes.TimelineController.PostNotExist); - } - - long postId; - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - postId = body.Id; - } - - { - var res = await client.GetAsync(generator(1, $"posts/{postId}/data")); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.PostNoData); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Timeline_LastModified(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - DateTime lastModified; - - { - var res = await client.GetAsync(generator(1)); - lastModified = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified; - } - - await Task.Delay(1000); - - { - var res = await client.PatchAsJsonAsync(generator(1), new TimelinePatchRequest { Description = "123" }); - lastModified = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().BeAfter(lastModified).And.Subject.Value; - } - - { - var res = await client.GetAsync(generator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().Be(lastModified); - } - - await Task.Delay(1000); - - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.GetAsync(generator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().BeAfter(lastModified); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Post_ModifiedSince(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - var postContentList = new List { "a", "b", "c", "d" }; - var posts = new List(); - - foreach (var content in postContentList) - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); - var post = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - posts.Add(post); - await Task.Delay(1000); - } - - { - var res = await client.DeleteAsync(generator(1, $"posts/{posts[2].Id}")); - res.Should().BeDelete(true); - } - - { - var res = await client.GetAsync(generator(1, "posts", - new Dictionary { { "modifiedSince", posts[1].LastUpdated.ToString("s", CultureInfo.InvariantCulture) } })); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which.Should().HaveCount(2) - .And.Subject.Select(p => p.Content.Text).Should().Equal("b", "d"); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task PostList_IncludeDeleted(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - var postContentList = new List { "a", "b", "c", "d" }; - var posts = new List(); - - foreach (var content in postContentList) - { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), - new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); - posts.Add(res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which); - } - - foreach (var id in new long[] { posts[0].Id, posts[2].Id }) - { - var res = await client.DeleteAsync(urlGenerator(1, $"posts/{id}")); - res.Should().BeDelete(true); - } - - { - var res = await client.GetAsync(urlGenerator(1, "posts", new Dictionary { ["includeDeleted"] = "true" })); - posts = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - posts.Should().HaveCount(4); - posts.Select(p => p.Deleted).Should().Equal(true, false, true, false); - posts.Select(p => p.Content == null).Should().Equal(true, false, true, false); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Post_ModifiedSince_And_IncludeDeleted(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - var postContentList = new List { "a", "b", "c", "d" }; - var posts = new List(); - - foreach (var (content, index) in postContentList.Select((v, i) => (v, i))) - { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), - new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); - var post = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - posts.Add(post); - await Task.Delay(1000); - } - - { - var res = await client.DeleteAsync(urlGenerator(1, $"posts/{posts[2].Id}")); - res.Should().BeDelete(true); - } - - { - - var res = await client.GetAsync(urlGenerator(1, "posts", - new Dictionary { - { "modifiedSince", posts[1].LastUpdated.ToString("s", CultureInfo.InvariantCulture) }, - { "includeDeleted", "true" } - })); - posts = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - posts.Should().HaveCount(3); - posts.Select(p => p.Deleted).Should().Equal(false, true, false); - posts.Select(p => p.Content == null).Should().Equal(false, true, false); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Timeline_Get_IfModifiedSince_And_CheckUniqueId(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - DateTime lastModifiedTime; - TimelineInfo timeline; - string uniqueId; - - { - var res = await client.GetAsync(urlGenerator(1)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - timeline = body; - lastModifiedTime = body.LastModified; - uniqueId = body.UniqueId; - } - - { - using var req = new HttpRequestMessage - { - RequestUri = new Uri(client.BaseAddress, urlGenerator(1)), - Method = HttpMethod.Get, - }; - req.Headers.IfModifiedSince = lastModifiedTime.AddSeconds(1); - var res = await client.SendAsync(req); - res.Should().HaveStatusCode(304); - } - - { - using var req = new HttpRequestMessage - { - RequestUri = new Uri(client.BaseAddress, urlGenerator(1)), - Method = HttpMethod.Get, - }; - req.Headers.IfModifiedSince = lastModifiedTime.AddSeconds(-1); - var res = await client.SendAsync(req); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timeline); - } - - { - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) } })); - res.Should().HaveStatusCode(304); - } - - { - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(-1).ToString("s", CultureInfo.InvariantCulture) } })); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timeline); - } - - { - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }, - {"checkUniqueId", uniqueId } })); - res.Should().HaveStatusCode(304); - } - - { - var testUniqueId = (uniqueId[0] == 'a' ? "b" : "a") + uniqueId[1..]; - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }, - {"checkUniqueId", testUniqueId } })); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timeline); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Title(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - { - var res = await client.GetAsync(urlGenerator(1)); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - timeline.Title.Should().Be(timeline.Name); - } - - { - var res = await client.PatchAsJsonAsync(urlGenerator(1), new TimelinePatchRequest { Title = "atitle" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Title.Should().Be("atitle"); - } - - { - var res = await client.GetAsync(urlGenerator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Title.Should().Be("atitle"); - } - } - - [Fact] - public async Task ChangeName() - { - { - using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); - res.Should().HaveStatusCode(401); - } - - { - using var client = await CreateClientAs(2); - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); - res.Should().HaveStatusCode(403); - } - - using (var client = await CreateClientAsUser()) - { - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "!!!", NewName = "tttttttt" }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttt", NewName = "!!!!" }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttttt", NewName = "tttttttt" }); - res.Should().HaveStatusCode(400).And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.TimelineController.NotExist); - } - - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "newt" }); - res.Should().HaveStatusCode(200).And.HaveJsonBody().Which.Name.Should().Be("newt"); - } - - { - var res = await client.GetAsync("timelines/t1"); - res.Should().HaveStatusCode(404); - } - - { - var res = await client.GetAsync("timelines/newt"); - res.Should().HaveStatusCode(200).And.HaveJsonBody().Which.Name.Should().Be("newt"); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task PostDataETag(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - long id; - string etag; - - { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), new TimelinePostCreateRequest - { - Content = new TimelinePostCreateRequestContent - { - Type = TimelinePostContentTypes.Image, - Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 50)) - } - }); - res.Should().HaveStatusCode(200); - var body = await res.ReadBodyAsJsonAsync(); - body.Content.ETag.Should().NotBeNullOrEmpty(); - - id = body.Id; - etag = body.Content.ETag; - } - - { - var res = await client.GetAsync(urlGenerator(1, $"posts/{id}/data")); - res.Should().HaveStatusCode(200); - res.Headers.ETag.Should().NotBeNull(); - res.Headers.ETag.ToString().Should().Be(etag); - } - } - } -} diff --git a/Timeline.Tests/IntegratedTests/TokenTest.cs b/Timeline.Tests/IntegratedTests/TokenTest.cs deleted file mode 100644 index 480d66cd..00000000 --- a/Timeline.Tests/IntegratedTests/TokenTest.cs +++ /dev/null @@ -1,165 +0,0 @@ -using FluentAssertions; -using Microsoft.Extensions.DependencyInjection; -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Timeline.Models; -using Timeline.Models.Http; -using Timeline.Services; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class TokenTest : IntegratedTestBase - { - private const string CreateTokenUrl = "token/create"; - private const string VerifyTokenUrl = "token/verify"; - - private static async Task CreateUserTokenAsync(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().Which; - } - - public static IEnumerable CreateToken_InvalidModel_Data() - { - yield return new[] { null, "p", null }; - yield return new[] { "u", null, null }; - yield return new object[] { "u", "p", 2000 }; - yield return new object[] { "u", "p", -1 }; - } - - [Theory] - [MemberData(nameof(CreateToken_InvalidModel_Data))] - public async Task CreateToken_InvalidModel(string username, string password, int expire) - { - using var client = await CreateDefaultClient(); - (await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest - { - Username = username, - Password = password, - Expire = expire - })).Should().BeInvalidModel(); - } - - public static IEnumerable CreateToken_UserCredential_Data() - { - yield return new[] { "usernotexist", "p" }; - yield return new[] { "user1", "???" }; - } - - [Theory] - [MemberData(nameof(CreateToken_UserCredential_Data))] - public async void CreateToken_UserCredential(string username, string password) - { - using var client = await CreateDefaultClient(); - var response = await client.PostAsJsonAsync(CreateTokenUrl, - new CreateTokenRequest { Username = username, Password = password }); - response.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Create_BadCredential); - } - - [Fact] - public async Task CreateToken_Success() - { - using var client = await CreateDefaultClient(); - var response = await client.PostAsJsonAsync(CreateTokenUrl, - new CreateTokenRequest { Username = "user1", Password = "user1pw" }); - var body = response.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Token.Should().NotBeNullOrWhiteSpace(); - body.User.Should().BeEquivalentTo(UserInfos[1]); - } - - [Fact] - public async Task VerifyToken_InvalidModel() - { - using var client = await CreateDefaultClient(); - (await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = null })).Should().BeInvalidModel(); - } - - [Fact] - public async Task VerifyToken_BadFormat() - { - using var client = await CreateDefaultClient(); - var response = await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = "bad token hahaha" }); - response.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Verify_BadFormat); - } - - [Fact] - public async Task VerifyToken_OldVersion() - { - using var client = await CreateDefaultClient(); - var token = (await CreateUserTokenAsync(client, "user1", "user1pw")).Token; - - using (var scope = TestApp.Host.Services.CreateScope()) // UserService is scoped. - { - // create a user for test - var userService = scope.ServiceProvider.GetRequiredService(); - await userService.ModifyUser("user1", new User { Password = "user1pw" }); - } - - (await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = token })) - .Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Verify_OldVersion); - } - - [Fact] - public async Task VerifyToken_UserNotExist() - { - using var client = await CreateDefaultClient(); - var token = (await CreateUserTokenAsync(client, "user1", "user1pw")).Token; - - using (var scope = TestApp.Host.Services.CreateScope()) // UserDeleteService is scoped. - { - var userService = scope.ServiceProvider.GetRequiredService(); - await userService.DeleteUser("user1"); - } - - (await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = token })) - .Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Verify_UserNotExist); - } - - //[Fact] - //public async Task VerifyToken_Expired() - //{ - // using (var client = await CreateClientWithNoAuth()) - // { - // // I can only control the token expired time but not current time - // // because verify logic is encapsuled in other library. - // var mockClock = _factory.GetTestClock(); - // mockClock.MockCurrentTime = DateTime.Now - TimeSpan.FromDays(2); - // var token = (await client.CreateUserTokenAsync(MockUsers.UserUsername, MockUsers.UserPassword, 1)).Token; - // var response = await client.PostAsJsonAsync(VerifyTokenUrl, - // new VerifyTokenRequest { Token = token }); - // response.Should().HaveStatusCodeBadRequest() - // .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Verify_Expired); - // mockClock.MockCurrentTime = null; - // } - //} - - [Fact] - public async Task VerifyToken_Success() - { - using var client = await CreateDefaultClient(); - var createTokenResult = await CreateUserTokenAsync(client, "user1", "user1pw"); - var response = await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = createTokenResult.Token }); - response.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.User.Should().BeEquivalentTo(UserInfos[1]); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs b/Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs deleted file mode 100644 index 732232e2..00000000 --- a/Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FluentAssertions; -using System.Threading.Tasks; -using Timeline.Models.Http; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class UnknownEndpointTest : IntegratedTestBase - { - [Fact] - public async Task UnknownEndpoint() - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync("unknownEndpoint"); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.Common.UnknownEndpoint); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs deleted file mode 100644 index f2796005..00000000 --- a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ /dev/null @@ -1,251 +0,0 @@ -using FluentAssertions; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Gif; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.Formats.Png; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Mime; -using System.Threading.Tasks; -using Timeline.Models.Http; -using Timeline.Services; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class UserAvatarTest : IntegratedTestBase - { - [Fact] - public async Task Test() - { - Avatar mockAvatar = new Avatar - { - Data = ImageHelper.CreatePngWithSize(100, 100), - Type = PngFormat.Instance.DefaultMimeType - }; - - using (var client = await CreateClientAsUser()) - { - { - var res = await client.GetAsync("users/usernotexist/avatar"); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - - var env = TestApp.Host.Services.GetRequiredService(); - var defaultAvatarData = await File.ReadAllBytesAsync(Path.Combine(env.ContentRootPath, "default-avatar.png")); - - async Task GetReturnDefault(string username = "user1") - { - var res = await client.GetAsync($"users/{username}/avatar"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be("image/png"); - var body = await res.Content.ReadAsByteArrayAsync(); - body.Should().Equal(defaultAvatarData); - } - - { - var res = await client.GetAsync("users/user1/avatar"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be("image/png"); - var body = await res.Content.ReadAsByteArrayAsync(); - body.Should().Equal(defaultAvatarData); - } - - await CacheTestHelper.TestCache(client, "users/user1/avatar"); - - await GetReturnDefault("admin"); - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 1; - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 0; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", new[] { (byte)0x00 }, "image/notaccept"); - res.Should().HaveStatusCode(HttpStatusCode.UnsupportedMediaType); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 1000 * 1000 * 11; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Common.Content.TooBig); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 2; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00, (byte)0x01 }); - content.Headers.ContentLength = 1; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", new[] { (byte)0x00 }, "image/png"); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserAvatar.BadFormat_CantDecode); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", mockAvatar.Data, "image/jpeg"); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserAvatar.BadFormat_UnmatchedFormat); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", ImageHelper.CreatePngWithSize(100, 200), "image/png"); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserAvatar.BadFormat_BadSize); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.Type); - res.Should().HaveStatusCode(HttpStatusCode.OK); - - var res2 = await client.GetAsync("users/user1/avatar"); - res2.Should().HaveStatusCode(200); - res2.Content.Headers.ContentType.MediaType.Should().Be(mockAvatar.Type); - var body = await res2.Content.ReadAsByteArrayAsync(); - body.Should().Equal(mockAvatar.Data); - } - - IEnumerable<(string, IImageFormat)> formats = new (string, IImageFormat)[] - { - ("image/jpeg", JpegFormat.Instance), - ("image/gif", GifFormat.Instance), - ("image/png", PngFormat.Instance), - }; - - foreach ((var mimeType, var format) in formats) - { - var res = await client.PutByteArrayAsync("users/user1/avatar", ImageHelper.CreateImageWithSize(100, 100, format), mimeType); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - var res = await client.PutByteArrayAsync("users/admin/avatar", new[] { (byte)0x00 }, "image/png"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Common.Forbid); - } - - { - var res = await client.DeleteAsync("users/admin/avatar"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Common.Forbid); - } - - for (int i = 0; i < 2; i++) // double delete should work. - { - var res = await client.DeleteAsync("users/user1/avatar"); - res.Should().HaveStatusCode(200); - await GetReturnDefault(); - } - } - - // Authorization check. - using (var client = await CreateClientAsAdministrator()) - { - { - var res = await client.PutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.Type); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - var res = await client.DeleteAsync("users/user1/avatar"); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - var res = await client.PutByteArrayAsync("users/usernotexist/avatar", new[] { (byte)0x00 }, "image/png"); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - - { - var res = await client.DeleteAsync("users/usernotexist/avatar"); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - } - - // bad username check - using (var client = await CreateClientAsAdministrator()) - { - { - var res = await client.GetAsync("users/u!ser/avatar"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PutByteArrayAsync("users/u!ser/avatar", ImageHelper.CreatePngWithSize(100, 100), "image/png"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.DeleteAsync("users/u!ser/avatar"); - res.Should().BeInvalidModel(); - } - } - } - - [Fact] - public async Task AvatarPutReturnETag() - { - using var client = await CreateClientAsUser(); - - EntityTagHeaderValue etag; - - { - var image = ImageHelper.CreatePngWithSize(100, 100); - var res = await client.PutByteArrayAsync("users/user1/avatar", image, PngFormat.Instance.DefaultMimeType); - res.Should().HaveStatusCode(200); - etag = res.Headers.ETag; - etag.Should().NotBeNull(); - etag.Tag.Should().NotBeNullOrEmpty(); - } - - { - var res = await client.GetAsync("users/user1/avatar"); - res.Should().HaveStatusCode(200); - res.Headers.ETag.Should().Be(etag); - res.Headers.ETag.Tag.Should().Be(etag.Tag); - } - } - } -} \ No newline at end of file diff --git a/Timeline.Tests/IntegratedTests/UserTest.cs b/Timeline.Tests/IntegratedTests/UserTest.cs deleted file mode 100644 index 9dfcc6a5..00000000 --- a/Timeline.Tests/IntegratedTests/UserTest.cs +++ /dev/null @@ -1,447 +0,0 @@ -using FluentAssertions; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Timeline.Models.Http; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class UserTest : IntegratedTestBase - { - [Fact] - public void UserListShouldHaveUniqueId() - { - foreach (var user in UserInfos) - { - user.UniqueId.Should().NotBeNullOrWhiteSpace(); - } - } - - [Fact] - public async Task GetList_NoAuth() - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync("users"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos); - } - - [Fact] - public async Task GetList_User() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync("users"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos); - } - - [Fact] - public async Task GetList_Admin() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.GetAsync("users"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos); - } - - [Fact] - public async Task Get_NoAuth() - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync($"users/admin"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos[0]); - } - - [Fact] - public async Task Get_User() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync($"users/admin"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos[0]); - } - - [Fact] - public async Task Get_Admin() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.GetAsync($"users/user1"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos[1]); - } - - [Fact] - public async Task Get_InvalidModel() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync("users/aaa!a"); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Get_404() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync("users/usernotexist"); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody(ErrorCodes.UserCommon.NotExist); - } - - [Fact] - public async Task Patch_User() - { - using var client = await CreateClientAsUser(); - { - var res = await client.PatchAsJsonAsync("users/user1", - new UserPatchRequest { Nickname = "aaa" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Nickname.Should().Be("aaa"); - } - - { - var res = await client.GetAsync("users/user1"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Nickname.Should().Be("aaa"); - } - } - - [Fact] - public async Task Patch_Admin() - { - using var client = await CreateClientAsAdministrator(); - using var userClient = await CreateClientAsUser(); - - { - var res = await client.PatchAsJsonAsync("users/user1", - new UserPatchRequest - { - Username = "newuser", - Password = "newpw", - Administrator = true, - Nickname = "aaa" - }); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Administrator.Should().Be(true); - body.Nickname.Should().Be("aaa"); - } - - { - var res = await client.GetAsync("users/newuser"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Administrator.Should().Be(true); - body.Nickname.Should().Be("aaa"); - } - - { - // Token should expire. - var res = await userClient.GetAsync("testing/auth/Authorize"); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - { - // Check password. - (await CreateClientWithCredential("newuser", "newpw")).Dispose(); - } - } - - [Fact] - public async Task Patch_NotExist() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/usernotexist", new UserPatchRequest { }); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - - [Fact] - public async Task Patch_InvalidModel() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/aaa!a", new UserPatchRequest { }); - res.Should().BeInvalidModel(); - } - - public static IEnumerable Patch_InvalidModel_Body_Data() - { - yield return new[] { new UserPatchRequest { Username = "aaa!a" } }; - yield return new[] { new UserPatchRequest { Password = "" } }; - yield return new[] { new UserPatchRequest { Nickname = new string('a', 50) } }; - } - - [Theory] - [MemberData(nameof(Patch_InvalidModel_Body_Data))] - public async Task Patch_InvalidModel_Body(UserPatchRequest body) - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/user1", body); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Patch_UsernameConflict() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Username = "admin" }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.UserController.UsernameConflict); - } - - [Fact] - public async Task Patch_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Nickname = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - [Fact] - public async Task Patch_User_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/admin", new UserPatchRequest { Nickname = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Patch_Username_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Username = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Patch_Password_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Password = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Patch_Administrator_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Administrator = true }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Delete_Deleted() - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.DeleteAsync("users/user1"); - res.Should().BeDelete(true); - } - - { - var res = await client.GetAsync("users/user1"); - res.Should().HaveStatusCode(404); - } - } - - [Fact] - public async Task Delete_NotExist() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.DeleteAsync("users/usernotexist"); - res.Should().BeDelete(false); - } - - [Fact] - public async Task Delete_InvalidModel() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.DeleteAsync("users/aaa!a"); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Delete_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync("users/aaa!a"); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - [Fact] - public async Task Delete_User_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.DeleteAsync("users/aaa!a"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - private const string createUserUrl = "userop/createuser"; - - [Fact] - public async Task Op_CreateUser() - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "aaa", - Password = "bbb", - Administrator = true, - Nickname = "ccc" - }); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Username.Should().Be("aaa"); - body.Nickname.Should().Be("ccc"); - body.Administrator.Should().BeTrue(); - } - { - var res = await client.GetAsync("users/aaa"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Username.Should().Be("aaa"); - body.Nickname.Should().Be("ccc"); - body.Administrator.Should().BeTrue(); - } - { - // Test password. - (await CreateClientWithCredential("aaa", "bbb")).Dispose(); - } - } - - public static IEnumerable Op_CreateUser_InvalidModel_Data() - { - yield return new[] { new CreateUserRequest { Username = "aaa", Password = "bbb" } }; - yield return new[] { new CreateUserRequest { Username = "aaa", Administrator = true } }; - yield return new[] { new CreateUserRequest { Password = "bbb", Administrator = true } }; - yield return new[] { new CreateUserRequest { Username = "a!a", Password = "bbb", Administrator = true } }; - yield return new[] { new CreateUserRequest { Username = "aaa", Password = "", Administrator = true } }; - yield return new[] { new CreateUserRequest { Username = "aaa", Password = "bbb", Administrator = true, Nickname = new string('a', 40) } }; - } - - [Theory] - [MemberData(nameof(Op_CreateUser_InvalidModel_Data))] - public async Task Op_CreateUser_InvalidModel(CreateUserRequest body) - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.PostAsJsonAsync(createUserUrl, body); - res.Should().BeInvalidModel(); - } - } - - [Fact] - public async Task Op_CreateUser_UsernameConflict() - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "user1", - Password = "bbb", - Administrator = false - }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.UserController.UsernameConflict); - } - } - - [Fact] - public async Task Op_CreateUser_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "aaa", - Password = "bbb", - Administrator = false - }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - } - - [Fact] - public async Task Op_CreateUser_User_Forbid() - { - using var client = await CreateClientAsUser(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "aaa", - Password = "bbb", - Administrator = false - }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - } - - private const string changePasswordUrl = "userop/changepassword"; - - [Fact] - public async Task Op_ChangePassword() - { - using var client = await CreateClientAsUser(); - { - var res = await client.PostAsJsonAsync(changePasswordUrl, - new ChangePasswordRequest { OldPassword = "user1pw", NewPassword = "newpw" }); - res.Should().HaveStatusCode(200); - } - { - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - { - (await CreateClientWithCredential("user1", "newpw")).Dispose(); - } - } - - public static IEnumerable Op_ChangePassword_InvalidModel_Data() - { - yield return new[] { null, "ppp" }; - yield return new[] { "ppp", null }; - } - - [Theory] - [MemberData(nameof(Op_ChangePassword_InvalidModel_Data))] - public async Task Op_ChangePassword_InvalidModel(string oldPassword, string newPassword) - { - using var client = await CreateClientAsUser(); - var res = await client.PostAsJsonAsync(changePasswordUrl, - new ChangePasswordRequest { OldPassword = oldPassword, NewPassword = newPassword }); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Op_ChangePassword_BadOldPassword() - { - using var client = await CreateClientAsUser(); - var res = await client.PostAsJsonAsync(changePasswordUrl, new ChangePasswordRequest { OldPassword = "???", NewPassword = "???" }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.UserController.ChangePassword_BadOldPassword); - } - - [Fact] - public async Task Op_ChangePassword_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync(changePasswordUrl, new ChangePasswordRequest { OldPassword = "???", NewPassword = "???" }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - } -} diff --git a/Timeline.Tests/PasswordGenerator.cs b/Timeline.Tests/PasswordGenerator.cs deleted file mode 100644 index 863439b5..00000000 --- a/Timeline.Tests/PasswordGenerator.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Timeline.Services; -using Xunit; -using Xunit.Abstractions; - -namespace Timeline.Tests -{ - public class PasswordGenerator - { - private readonly ITestOutputHelper _output; - - public PasswordGenerator(ITestOutputHelper output) - { - _output = output; - } - - [Fact] - public void Generate() - { - var service = new PasswordService(); - _output.WriteLine(service.HashPassword("crupest")); - } - } -} diff --git a/Timeline.Tests/Properties/launchSettings.json b/Timeline.Tests/Properties/launchSettings.json deleted file mode 100644 index f3ee419d..00000000 --- a/Timeline.Tests/Properties/launchSettings.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/Timeline.Tests/Services/TimelineServiceTest.cs b/Timeline.Tests/Services/TimelineServiceTest.cs deleted file mode 100644 index 5a774b78..00000000 --- a/Timeline.Tests/Services/TimelineServiceTest.cs +++ /dev/null @@ -1,329 +0,0 @@ -using FluentAssertions; -using Microsoft.Extensions.Logging.Abstractions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Models; -using Timeline.Services; -using Timeline.Services.Exceptions; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.Services -{ - public class TimelineServiceTest : IAsyncLifetime, IDisposable - { - private readonly TestDatabase _testDatabase = new TestDatabase(); - - private DatabaseContext _databaseContext; - - private readonly PasswordService _passwordService = new PasswordService(); - - private readonly ETagGenerator _eTagGenerator = new ETagGenerator(); - - private readonly ImageValidator _imageValidator = new ImageValidator(); - - private readonly TestClock _clock = new TestClock(); - - private DataManager _dataManager; - - private UserService _userService; - - private TimelineService _timelineService; - - private UserDeleteService _userDeleteService; - - public TimelineServiceTest() - { - } - - public async Task InitializeAsync() - { - await _testDatabase.InitializeAsync(); - _databaseContext = _testDatabase.CreateContext(); - _dataManager = new DataManager(_databaseContext, _eTagGenerator); - _userService = new UserService(NullLogger.Instance, _databaseContext, _passwordService, _clock); - _timelineService = new TimelineService(NullLogger.Instance, _databaseContext, _dataManager, _userService, _imageValidator, _clock); - _userDeleteService = new UserDeleteService(NullLogger.Instance, _databaseContext, _timelineService); - } - - public async Task DisposeAsync() - { - await _testDatabase.DisposeAsync(); - await _databaseContext.DisposeAsync(); - } - - public void Dispose() - { - _eTagGenerator.Dispose(); - } - - [Theory] - [InlineData("@user")] - [InlineData("tl")] - public async Task Timeline_GetLastModified(string timelineName) - { - var time = _clock.ForwardCurrentTime(); - - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - await _timelineService.CreateTimeline(timelineName, await _userService.GetUserIdByUsername("user")); - - var t = await _timelineService.GetTimelineLastModifiedTime(timelineName); - - t.Should().Be(time); - } - - [Theory] - [InlineData("@user")] - [InlineData("tl")] - public async Task Timeline_GetUnqiueId(string timelineName) - { - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - await _timelineService.CreateTimeline(timelineName, await _userService.GetUserIdByUsername("user")); - - var uniqueId = await _timelineService.GetTimelineUniqueId(timelineName); - - uniqueId.Should().NotBeNullOrEmpty(); - } - - [Theory] - [InlineData("@user")] - [InlineData("tl")] - public async Task Timeline_LastModified(string timelineName) - { - var initTime = _clock.ForwardCurrentTime(); - - void Check(Models.Timeline timeline) - { - timeline.NameLastModified.Should().Be(initTime); - timeline.LastModified.Should().Be(_clock.GetCurrentTime()); - } - - async Task GetAndCheck() - { - Check(await _timelineService.GetTimeline(timelineName)); - } - - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - Check(await _timelineService.CreateTimeline(timelineName, await _userService.GetUserIdByUsername("user"))); - - await GetAndCheck(); - - _clock.ForwardCurrentTime(); - await _timelineService.ChangeProperty(timelineName, new TimelineChangePropertyRequest { Visibility = TimelineVisibility.Public }); - await GetAndCheck(); - - _clock.ForwardCurrentTime(); - await _timelineService.ChangeMember(timelineName, new List { "admin" }, null); - await GetAndCheck(); - } - - [Theory] - [InlineData("@user")] - [InlineData("tl")] - public async Task GetPosts_ModifiedSince(string timelineName) - { - _clock.ForwardCurrentTime(); - - var userId = await _userService.GetUserIdByUsername("user"); - - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - await _timelineService.CreateTimeline(timelineName, userId); - - var postContentList = new string[] { "a", "b", "c", "d" }; - - DateTime testPoint = new DateTime(); - - foreach (var (content, index) in postContentList.Select((v, i) => (v, i))) - { - var t = _clock.ForwardCurrentTime(); - if (index == 1) - testPoint = t; - await _timelineService.CreateTextPost(timelineName, userId, content, null); - } - - var posts = await _timelineService.GetPosts(timelineName, testPoint); - posts.Should().HaveCount(3) - .And.Subject.Select(p => (p.Content as TextTimelinePostContent).Text).Should().Equal(postContentList.Skip(1)); - } - - [Theory] - [InlineData("@user")] - [InlineData("tl")] - public async Task GetPosts_IncludeDeleted(string timelineName) - { - var userId = await _userService.GetUserIdByUsername("user"); - - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - await _timelineService.CreateTimeline(timelineName, userId); - - var postContentList = new string[] { "a", "b", "c", "d" }; - - foreach (var content in postContentList) - { - await _timelineService.CreateTextPost(timelineName, userId, content, null); - } - - var posts = await _timelineService.GetPosts(timelineName); - posts.Should().HaveCount(4); - posts.Select(p => p.Deleted).Should().Equal(Enumerable.Repeat(false, posts.Count)); - posts.Select(p => ((TextTimelinePostContent)p.Content).Text).Should().Equal(postContentList); - - foreach (var id in new long[] { posts[0].Id, posts[2].Id }) - { - await _timelineService.DeletePost(timelineName, id); - } - - posts = await _timelineService.GetPosts(timelineName); - posts.Should().HaveCount(2); - posts.Select(p => p.Deleted).Should().Equal(Enumerable.Repeat(false, posts.Count)); - posts.Select(p => ((TextTimelinePostContent)p.Content).Text).Should().Equal(new string[] { "b", "d" }); - - posts = await _timelineService.GetPosts(timelineName, includeDeleted: true); - posts.Should().HaveCount(4); - posts.Select(p => p.Deleted).Should().Equal(new bool[] { true, false, true, false }); - posts.Where(p => !p.Deleted).Select(p => ((TextTimelinePostContent)p.Content).Text).Should().Equal(new string[] { "b", "d" }); - } - - [Theory] - [InlineData("@admin")] - [InlineData("tl")] - public async Task GetPosts_ModifiedSince_UsernameChange(string timelineName) - { - var time1 = _clock.ForwardCurrentTime(); - - var userId = await _userService.GetUserIdByUsername("user"); - - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - await _timelineService.CreateTimeline(timelineName, userId); - - var postContentList = new string[] { "a", "b", "c", "d" }; - - foreach (var (content, index) in postContentList.Select((v, i) => (v, i))) - { - await _timelineService.CreateTextPost(timelineName, userId, content, null); - } - - var time2 = _clock.ForwardCurrentTime(); - - { - var posts = await _timelineService.GetPosts(timelineName, time2); - posts.Should().HaveCount(0); - } - - { - await _userService.ModifyUser(userId, new User { Nickname = "haha" }); - var posts = await _timelineService.GetPosts(timelineName, time2); - posts.Should().HaveCount(0); - } - - { - await _userService.ModifyUser(userId, new User { Username = "haha" }); - var posts = await _timelineService.GetPosts(timelineName, time2); - posts.Should().HaveCount(4); - } - } - - [Theory] - [InlineData("@admin")] - [InlineData("tl")] - public async Task GetPosts_ModifiedSince_UserDelete(string timelineName) - { - var time1 = _clock.ForwardCurrentTime(); - - var userId = await _userService.GetUserIdByUsername("user"); - var adminId = await _userService.GetUserIdByUsername("admin"); - - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - await _timelineService.CreateTimeline(timelineName, adminId); - - var postContentList = new string[] { "a", "b", "c", "d" }; - - foreach (var (content, index) in postContentList.Select((v, i) => (v, i))) - { - await _timelineService.CreateTextPost(timelineName, userId, content, null); - } - - var time2 = _clock.ForwardCurrentTime(); - - { - var posts = await _timelineService.GetPosts(timelineName, time2); - posts.Should().HaveCount(0); - } - - await _userDeleteService.DeleteUser("user"); - - { - var posts = await _timelineService.GetPosts(timelineName, time2); - posts.Should().HaveCount(0); - } - - { - var posts = await _timelineService.GetPosts(timelineName, time2, true); - posts.Should().HaveCount(4); - } - } - - [Theory] - [InlineData("@admin")] - [InlineData("tl")] - public async Task Title(string timelineName) - { - var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); - if (!isPersonal) - await _timelineService.CreateTimeline(timelineName, await _userService.GetUserIdByUsername("user")); - - { - var timeline = await _timelineService.GetTimeline(timelineName); - timeline.Title.Should().Be(timelineName); - } - - { - await _timelineService.ChangeProperty(timelineName, new TimelineChangePropertyRequest { Title = null }); - var timeline = await _timelineService.GetTimeline(timelineName); - timeline.Title.Should().Be(timelineName); - } - - { - await _timelineService.ChangeProperty(timelineName, new TimelineChangePropertyRequest { Title = "atitle" }); - var timeline = await _timelineService.GetTimeline(timelineName); - timeline.Title.Should().Be("atitle"); - } - } - - [Fact] - public async Task ChangeName() - { - _clock.ForwardCurrentTime(); - - await _timelineService.Awaiting(s => s.ChangeTimelineName("!!!", "newtl")).Should().ThrowAsync(); - await _timelineService.Awaiting(s => s.ChangeTimelineName("tl", "!!!")).Should().ThrowAsync(); - await _timelineService.Awaiting(s => s.ChangeTimelineName("tl", "newtl")).Should().ThrowAsync(); - - await _timelineService.CreateTimeline("tl", await _userService.GetUserIdByUsername("user")); - await _timelineService.CreateTimeline("tl2", await _userService.GetUserIdByUsername("user")); - - await _timelineService.Awaiting(s => s.ChangeTimelineName("tl", "tl2")).Should().ThrowAsync(); - - var time = _clock.ForwardCurrentTime(); - - await _timelineService.ChangeTimelineName("tl", "newtl"); - - { - var timeline = await _timelineService.GetTimeline("newtl"); - timeline.Name.Should().Be("newtl"); - timeline.LastModified.Should().Be(time); - timeline.NameLastModified.Should().Be(time); - } - } - } -} diff --git a/Timeline.Tests/Timeline.Tests.csproj b/Timeline.Tests/Timeline.Tests.csproj deleted file mode 100644 index 973e0fc0..00000000 --- a/Timeline.Tests/Timeline.Tests.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - - netcoreapp3.1 - - 8.0 - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - diff --git a/Timeline.Tests/UsernameValidatorUnitTest.cs b/Timeline.Tests/UsernameValidatorUnitTest.cs deleted file mode 100644 index 5b568adf..00000000 --- a/Timeline.Tests/UsernameValidatorUnitTest.cs +++ /dev/null @@ -1,78 +0,0 @@ -using FluentAssertions; -using Timeline.Models.Validation; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests -{ - public class UsernameValidatorUnitTest : IClassFixture - { - private readonly UsernameValidator _validator; - - public UsernameValidatorUnitTest(UsernameValidator validator) - { - _validator = validator; - } - - private string FailAndMessage(string username) - { - var (result, message) = _validator.Validate(username); - result.Should().BeFalse(); - return message; - } - - [Fact] - public void NotString() - { - var (result, message) = _validator.Validate(123); - result.Should().BeFalse(); - message.Should().ContainEquivalentOf("type"); - } - - [Fact] - public void Empty() - { - FailAndMessage("").Should().ContainEquivalentOf("empty"); - } - - [Theory] - [InlineData("!")] - [InlineData("!abc")] - [InlineData("ab c")] - [InlineData("ab c!")] // This is a chinese ! . - public void BadCharactor(string value) - { - FailAndMessage(value).Should().ContainEquivalentOf("invalid") - .And.ContainEquivalentOf("character"); - } - - [Fact] - public void TooLong() - { - FailAndMessage(new string('a', 40)).Should().ContainEquivalentOf("long"); - } - - [Fact(Skip = "Currently name can't be longer than 26. So this will print message of too long.")] - public void UniqueId() - { - FailAndMessage("e4c80127d092d9b2fc19c5e04612d4c0").Should().ContainEquivalentOf("unique id"); - } - - [Theory] - [InlineData(null)] - [InlineData("abc")] - [InlineData("-abc")] - [InlineData("_abc")] - [InlineData("abc-")] - [InlineData("abc_")] - [InlineData("a-bc")] - [InlineData("a-b-c")] - [InlineData("a-b_c")] - [InlineData("a-你好_c")] - public void Success(string value) - { - var (result, _) = _validator.Validate(value); - result.Should().BeTrue(); - } - } -} diff --git a/Timeline.Tests/coverletArgs.runsettings b/Timeline.Tests/coverletArgs.runsettings deleted file mode 100644 index 24cd1822..00000000 --- a/Timeline.Tests/coverletArgs.runsettings +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - [xunit.*]*,[Timeline]Timeline.Migrations.* - - - - - diff --git a/Timeline.Tests/packages.lock.json b/Timeline.Tests/packages.lock.json deleted file mode 100644 index 7150a222..00000000 --- a/Timeline.Tests/packages.lock.json +++ /dev/null @@ -1,2040 +0,0 @@ -{ - "version": 1, - "dependencies": { - ".NETCoreApp,Version=v3.1": { - "coverlet.collector": { - "type": "Direct", - "requested": "[1.3.0, )", - "resolved": "1.3.0", - "contentHash": "t8pnf5SX2ya0RX4vjoxsbhDMQCZJcpPun2neHKJ4FouMmObylo25FvoOydvf3Bl+l+IzWw7u2vjEeCBHnleB9g==" - }, - "FluentAssertions": { - "type": "Direct", - "requested": "[5.10.3, )", - "resolved": "5.10.3", - "contentHash": "gVPEVp1hLVqcv+7Q2wiDf7kqCNn7+bQcQ0jbJ2mcRT6CeRoZl1tNkqvzSIhvekyldDptk77j1b03MXTTRIqqpg==", - "dependencies": { - "System.Configuration.ConfigurationManager": "4.4.0" - } - }, - "JunitXml.TestLogger": { - "type": "Direct", - "requested": "[2.1.78, )", - "resolved": "2.1.78", - "contentHash": "4y4FSfKWxlked8ilQdqBBSeRMf5jD/Hkvyp744hc54yQcABLt4rR2Q+4hNqAqrSo+mhwAlusj2rpXpN/5TICCA==" - }, - "Microsoft.AspNet.WebApi.Client": { - "type": "Direct", - "requested": "[5.2.7, )", - "resolved": "5.2.7", - "contentHash": "/76fAHknzvFqbznS6Uj2sOyE9rJB3PltY+f53TH8dX9RiGhk02EhuFCWljSj5nnqKaTsmma8DFR50OGyQ4yJ1g==", - "dependencies": { - "Newtonsoft.Json": "10.0.1", - "Newtonsoft.Json.Bson": "1.0.1" - } - }, - "Microsoft.AspNetCore.TestHost": { - "type": "Direct", - "requested": "[3.1.9, )", - "resolved": "3.1.9", - "contentHash": "0DBtfgmM2yS4h0v+gS4JHRX4nuyQmW7Yi5/G4yB5KelA2dDXPsAiipw9z47B1jVEs9QZdOwSqPQm2R/owl2TnA==", - "dependencies": { - "System.IO.Pipelines": "4.7.3" - } - }, - "Microsoft.CodeAnalysis.FxCopAnalyzers": { - "type": "Direct", - "requested": "[3.3.0, )", - "resolved": "3.3.0", - "contentHash": "k3Icqx8kc+NrHImuiB8Jc/wd32Xeyd2B/7HOR5Qu9pyKzXQ4ikPeBAwzG2FSTuYhyIuNWvwL5k9yYBbbVz6w9w==", - "dependencies": { - "Microsoft.CodeAnalysis.VersionCheckAnalyzer": "[3.3.0]", - "Microsoft.CodeQuality.Analyzers": "[3.3.0]", - "Microsoft.NetCore.Analyzers": "[3.3.0]", - "Microsoft.NetFramework.Analyzers": "[3.3.0]" - } - }, - "Microsoft.NET.Test.Sdk": { - "type": "Direct", - "requested": "[16.7.1, )", - "resolved": "16.7.1", - "contentHash": "7T3XYuLT2CRMZXwlp8p4cEEf6y7VifxTdKwYNzCYp31CN4iyrcDKneIJvNTo0YVnTxJn+CSlGVlUnZHUlAwt9A==", - "dependencies": { - "Microsoft.CodeCoverage": "16.7.1", - "Microsoft.TestPlatform.TestHost": "16.7.1" - } - }, - "Moq": { - "type": "Direct", - "requested": "[4.14.7, )", - "resolved": "4.14.7", - "contentHash": "z1jwY3lL3d4l+92cdSnhRDUUco68HiRNfLKB9r9/PLP5lrN+ZL1Qtt3brVGVB8iY+ioBXhlFue2JtycBczE8Pw==", - "dependencies": { - "Castle.Core": "4.4.0", - "System.Threading.Tasks.Extensions": "4.5.1" - } - }, - "xunit": { - "type": "Direct", - "requested": "[2.4.1, )", - "resolved": "2.4.1", - "contentHash": "XNR3Yz9QTtec16O0aKcO6+baVNpXmOnPUxDkCY97J+8krUYxPvXT1szYYEUdKk4sB8GOI2YbAjRIOm8ZnXRfzQ==", - "dependencies": { - "xunit.analyzers": "0.10.0", - "xunit.assert": "[2.4.1]", - "xunit.core": "[2.4.1]" - } - }, - "xunit.runner.visualstudio": { - "type": "Direct", - "requested": "[2.4.3, )", - "resolved": "2.4.3", - "contentHash": "kZZSmOmKA8OBlAJaquPXnJJLM9RwQ27H7BMVqfMLUcTi9xHinWGJiWksa3D4NEtz0wZ/nxd2mogObvBgJKCRhQ==" - }, - "AutoMapper": { - "type": "Transitive", - "resolved": "10.1.1", - "contentHash": "uMgbqOdu9ZG5cIOty0C85hzzayBH2i9BthnS5FlMqKtMSHDv4ts81a2jS1VFaDBVhlBeIqJ/kQKjQY95BZde9w==", - "dependencies": { - "Microsoft.CSharp": "4.7.0", - "System.Reflection.Emit": "4.7.0" - } - }, - "AutoMapper.Extensions.Microsoft.DependencyInjection": { - "type": "Transitive", - "resolved": "8.1.0", - "contentHash": "dQyGCAYcHbGuimVvCMu4Ea2S1oYOlgO9XfVdClmY5wgygJMZoS57emPzH0qNfknmtzMm4QbDO9i237W5IDjU1A==", - "dependencies": { - "AutoMapper": "[10.1.0, 11.0.0)", - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.0.0", - "Microsoft.Extensions.Options": "3.0.0" - } - }, - "Castle.Core": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "b5rRL5zeaau1y/5hIbI+6mGw3cwun16YjkHZnV9RRT5UyUIFsgLmNXJ0YnIN9p8Hw7K7AbG1q1UclQVU3DinAQ==", - "dependencies": { - "NETStandard.Library": "1.6.1", - "System.Collections.Specialized": "4.3.0", - "System.ComponentModel": "4.3.0", - "System.ComponentModel.TypeConverter": "4.3.0", - "System.Diagnostics.TraceSource": "4.3.0", - "System.Dynamic.Runtime": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Xml.XmlDocument": "4.3.0" - } - }, - "Microsoft.AspNetCore.Authorization": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "cN2KJkfHcKwh82c9WGx4Tqfd2h5HflU/Mu5vYLMHON8WahHU9hE32ciIXcEIoKLNpu+zs1u1cN/qxcKTdqu89w==", - "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "1.0.2", - "Microsoft.Extensions.Options": "1.0.2", - "System.Security.Claims": "4.0.1" - } - }, - "Microsoft.AspNetCore.Hosting.Abstractions": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "ybY8FOkdNfBPB5PLv1JO+It/94ftBzGUI1WqU4XySbIWyhw2TPmmKAUuO9uvJoR0qpsFup8FJz6trsBcBITg9w==", - "dependencies": { - "Microsoft.AspNetCore.Hosting.Server.Abstractions": "1.0.4", - "Microsoft.AspNetCore.Http.Abstractions": "1.0.3", - "Microsoft.Extensions.Configuration.Abstractions": "1.0.2", - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.2", - "Microsoft.Extensions.FileProviders.Abstractions": "1.0.1", - "Microsoft.Extensions.Logging.Abstractions": "1.0.2" - } - }, - "Microsoft.AspNetCore.Hosting.Server.Abstractions": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "XUiQPe/CflK1i0Voo9S6/G1iQh00gQ6sMqi3LRtKeceBbO6AOostaAUdhjyME92MapI4VFNl+Z+/KXUlMAExJQ==", - "dependencies": { - "Microsoft.AspNetCore.Http.Features": "1.0.3", - "Microsoft.Extensions.Configuration.Abstractions": "1.0.2" - } - }, - "Microsoft.AspNetCore.Http": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "kfNOIGGgVtMzsSWZzXBqz5zsdo8ssBa90YHzZt95N8ARGXoolSaBHy6yBoMm/XcpbXM+m/x1fixTTMIWMgzJdQ==", - "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.0.3", - "Microsoft.AspNetCore.WebUtilities": "1.0.3", - "Microsoft.Extensions.ObjectPool": "1.0.1", - "Microsoft.Extensions.Options": "1.0.2", - "Microsoft.Net.Http.Headers": "1.0.3", - "System.Buffers": "4.0.0", - "System.Threading": "4.0.11" - } - }, - "Microsoft.AspNetCore.Http.Abstractions": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "nnjvAf7ag6P0DyD/0nhRGjLpv+3DkPU0juF8aQh46X8uF4kzjJdrh65oL+4PVOu3K6BgSg6OVUs0QC0SE0FRtg==", - "dependencies": { - "Microsoft.AspNetCore.Http.Features": "1.0.3", - "System.Globalization.Extensions": "4.0.1", - "System.Linq.Expressions": "4.1.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Text.Encodings.Web": "4.0.1" - } - }, - "Microsoft.AspNetCore.Http.Extensions": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "+7Sd+14nexIJqcB4S1Eur9kzeMZ5CBtrxkei+PNbD78fg8vO3+TcCgrl5SBNTsUB/VJAfD/s0fgs5t+hHRj2Pg==", - "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.0.3", - "Microsoft.Extensions.FileProviders.Abstractions": "1.0.1", - "Microsoft.Net.Http.Headers": "1.0.3", - "System.Buffers": "4.0.0", - "System.IO.FileSystem": "4.0.1" - } - }, - "Microsoft.AspNetCore.Http.Features": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "Ihq57tseNyPbJTmFXY4jQ4JkxLP0lh45VRwocQci/sFx+qcJGvWB+sJJ2/YPLy/qTWFAEfNAcswuY3OsNH9Gwg==", - "dependencies": { - "Microsoft.Extensions.Primitives": "1.0.1", - "System.Collections": "4.0.11", - "System.ComponentModel": "4.0.1", - "System.Linq": "4.1.0", - "System.Net.Primitives": "4.0.11", - "System.Net.WebSockets": "4.0.0", - "System.Runtime.Extensions": "4.1.0", - "System.Security.Claims": "4.0.1", - "System.Security.Cryptography.X509Certificates": "4.1.0", - "System.Security.Principal": "4.0.1" - } - }, - "Microsoft.AspNetCore.JsonPatch": { - "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "WVaSVS+dDlWCR/qerHnBxU9tIeJ9GMA3M5tg4cxH7/cJYZZLnr2zvaFHGB+cRRNCKKTJ0pFRxT7ES8knhgAAaA==", - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "Newtonsoft.Json": "9.0.1", - "System.Collections.Concurrent": "4.0.12", - "System.ComponentModel.TypeConverter": "4.1.0", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Serialization.Primitives": "4.1.1", - "System.Text.Encoding.Extensions": "4.0.11" - } - }, - "Microsoft.AspNetCore.Mvc.Abstractions": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "Isqgif1nuB+um86cEkpL8KnoxFCUCXBsbs9PuiuzElvlSiv4Ek3LvtrSUcbivekDDfys8CDbJhxwEI7WKJieAQ==", - "dependencies": { - "Microsoft.AspNetCore.Routing.Abstractions": "1.0.4", - "Microsoft.CSharp": "4.0.1", - "Microsoft.Net.Http.Headers": "1.0.3", - "System.ComponentModel.TypeConverter": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11" - } - }, - "Microsoft.AspNetCore.Mvc.ApiExplorer": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "ujCFTM42U2WKUBhdaoLoiI+wVHgYhrmDrkl5+hWJ7EJW4fhp42w4cRZ97tjuveWr+M6JZjpS0q+7PVofQzFUiw==", - "dependencies": { - "Microsoft.AspNetCore.Mvc.Core": "1.0.4" - } - }, - "Microsoft.AspNetCore.Mvc.Core": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "1ukcttN1+T82hWXE8WS5kawkruolKI6LPVqVI4rTzN16kFszS/UqTrcwSUEnmTRpmWgFo665V3c2GpdQ9B6znw==", - "dependencies": { - "Microsoft.AspNetCore.Authorization": "1.0.3", - "Microsoft.AspNetCore.Hosting.Abstractions": "1.0.3", - "Microsoft.AspNetCore.Http": "1.0.3", - "Microsoft.AspNetCore.Mvc.Abstractions": "1.0.4", - "Microsoft.AspNetCore.Routing": "1.0.4", - "Microsoft.Extensions.DependencyModel": "1.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "1.0.1", - "Microsoft.Extensions.Logging.Abstractions": "1.0.2", - "Microsoft.Extensions.PlatformAbstractions": "1.0.0", - "System.Buffers": "4.0.0", - "System.Diagnostics.DiagnosticSource": "4.0.0", - "System.Text.Encoding": "4.0.11" - } - }, - "Microsoft.AspNetCore.Mvc.Formatters.Json": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "i8WWK2GwlBHfOL+d+kknJWPks6DS9tbN6nfJZU4yb+/wfUAYd311B2CIHzdat3IewubnK1TYONwrhQcs2FbLeA==", - "dependencies": { - "Microsoft.AspNetCore.JsonPatch": "1.0.0", - "Microsoft.AspNetCore.Mvc.Core": "1.0.4" - } - }, - "Microsoft.AspNetCore.NodeServices": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "bbd3FlSPWiRQrIcBLa5TaOvo4gjmmiNMkxA8VmZ6u0eIpS0Yj35/eTopaGdtzqwlqj5jXbdRoib1MruXuPaW8A==", - "dependencies": { - "Microsoft.Extensions.Logging.Console": "3.1.9", - "Newtonsoft.Json": "12.0.2" - } - }, - "Microsoft.AspNetCore.Routing": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "mdIF3ckRothHWuCSFkk6YXACj5zxi5qM+cEAHjcpP04/wCHUoV0gGVnW+HI+LyFXE6JUwu2zXn5tfsCpW0U+SA==", - "dependencies": { - "Microsoft.AspNetCore.Http.Extensions": "1.0.3", - "Microsoft.AspNetCore.Routing.Abstractions": "1.0.4", - "Microsoft.Extensions.Logging.Abstractions": "1.0.2", - "Microsoft.Extensions.ObjectPool": "1.0.1", - "Microsoft.Extensions.Options": "1.0.2", - "System.Collections": "4.0.11", - "System.Text.RegularExpressions": "4.1.0" - } - }, - "Microsoft.AspNetCore.Routing.Abstractions": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "GHxVt6LlXHFsCUd2Un+/vY1tBTXxnogfbDO0b8G5EGmkapSK+dOGOLJviscxQkp338Uabs081JEIdkRymI5GXA==", - "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.0.3", - "System.Collections.Concurrent": "4.0.12", - "System.Reflection.Extensions": "4.0.1", - "System.Threading.Tasks": "4.0.11" - } - }, - "Microsoft.AspNetCore.SpaServices": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "Fb+N2ZyF1wNrGeWggT+Ovv6W8AAVxfi4V/SnuEsBOR+nmkFhty9zyh6IDRRS98GJK6OE3adqqPbWMtJqbxYnNA==", - "dependencies": { - "Microsoft.AspNetCore.NodeServices": "3.1.9" - } - }, - "Microsoft.AspNetCore.SpaServices.Extensions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "ciy2GCvRnh9C22laArLsaItS+72U6Hqf4nDYShdvFgcen2ZV+NNSitb/B3vsmFfIPM8m4mf2x4T+vZ6OlI5XaA==", - "dependencies": { - "Microsoft.AspNetCore.SpaServices": "3.1.9", - "Microsoft.Extensions.FileProviders.Physical": "3.1.9" - } - }, - "Microsoft.AspNetCore.StaticFiles": { - "type": "Transitive", - "resolved": "1.0.4", - "contentHash": "2pNvwewAazhaaCdw2CGUvIcDrNQMlqP57JgBDf3v+pRj1rZ29HVnpvkX6a+TrmRYlJNmmxHOKEt468uE/gDcFw==", - "dependencies": { - "Microsoft.AspNetCore.Hosting.Abstractions": "1.0.4", - "Microsoft.AspNetCore.Http.Extensions": "1.0.3", - "Microsoft.Extensions.FileProviders.Abstractions": "1.0.1", - "Microsoft.Extensions.Logging.Abstractions": "1.0.2", - "Microsoft.Extensions.WebEncoders": "1.0.3" - } - }, - "Microsoft.AspNetCore.WebUtilities": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "snSGNs5EEisqivDjDiskFkFyu+DV2Ib9sMPOBQKtoFwI5H1W5YNB/rIVqDZQL16zj/uzdwwxrdE/5xhkVyf6gQ==", - "dependencies": { - "Microsoft.Extensions.Primitives": "1.0.1", - "System.Buffers": "4.0.0", - "System.Collections": "4.0.11", - "System.IO": "4.1.0", - "System.IO.FileSystem": "4.0.1", - "System.Text.Encodings.Web": "4.0.1" - } - }, - "Microsoft.Bcl.AsyncInterfaces": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "yuvf07qFWFqtK3P/MRkEKLhn5r2UbSpVueRziSqj0yJQIKFwG1pq9mOayK3zE5qZCTs0CbrwL9M6R8VwqyGy2w==" - }, - "Microsoft.Bcl.HashCode": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "J2G1k+u5unBV+aYcwxo94ip16Rkp65pgWFb0R6zwJipzWNMgvqlWeuI7/+R+e8bob66LnSG+llLJ+z8wI94cHg==" - }, - "Microsoft.CodeAnalysis.VersionCheckAnalyzer": { - "type": "Transitive", - "resolved": "3.3.0", - "contentHash": "xjLM3DRFZMan3nQyBQEM1mBw6VqQybi4iMJhMFW6Ic1E1GCvqJR3ABOwEL7WtQjDUzxyrGld9bASnAos7G/Xyg==" - }, - "Microsoft.CodeCoverage": { - "type": "Transitive", - "resolved": "16.7.1", - "contentHash": "PhSppbk+kvAyD9yGJIcBRJ/XYwY+21YK88l22PGTtixaxNdjnx1idVKh88LCGwKaTL8HhlnQ41VmBiBdZJzIQw==" - }, - "Microsoft.CodeQuality.Analyzers": { - "type": "Transitive", - "resolved": "3.3.0", - "contentHash": "zZ3miq6u22UFQKhfJyLnVEJ+DgeOopLh3eKJnKAcOetPP2hiv3wa7kHZlBDeTvtqJQiAQhAVbttket8XxjN1zw==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" - }, - "Microsoft.Data.Sqlite.Core": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "+u4PeT1npi2EzhxGc5r1Z2z73zuXw+TlKVZm44WQhNCUw4LtUVDaxGSpUhrjW+X4snBCBfr4kT/uJyKnL4R4og==", - "dependencies": { - "SQLitePCLRaw.core": "2.0.2" - } - }, - "Microsoft.DotNet.PlatformAbstractions": { - "type": "Transitive", - "resolved": "3.1.6", - "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg==" - }, - "Microsoft.EntityFrameworkCore": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "u3A2W0BvAuAF2jgW+WX+C+Sh8sMGX5Kl1hdA0gu6A/XSrZQoW/BUP4a/q2n3iitDGndaorqjAKx+Spb9gBto+w==", - "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "1.1.1", - "Microsoft.Bcl.HashCode": "1.1.0", - "Microsoft.EntityFrameworkCore.Abstractions": "3.1.9", - "Microsoft.EntityFrameworkCore.Analyzers": "3.1.9", - "Microsoft.Extensions.Caching.Memory": "3.1.9", - "Microsoft.Extensions.DependencyInjection": "3.1.9", - "Microsoft.Extensions.Logging": "3.1.9", - "System.Collections.Immutable": "1.7.1", - "System.ComponentModel.Annotations": "4.7.0", - "System.Diagnostics.DiagnosticSource": "4.7.1" - } - }, - "Microsoft.EntityFrameworkCore.Abstractions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "IR6Y4RJVlw0QXdWXjF3Kx9s1QLiicJus+BFBKr43lBtriV20j3yrWMoaZ9W1AUUgnicZXpXVcNfklqtmwb9Sxw==" - }, - "Microsoft.EntityFrameworkCore.Analyzers": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "eXGyx/Lb1fiiKtnIStdxGrfBSSQg8oZytE10f1T/2xAx12W9dKB9U9fg05cwNCDC0S2CXILsmZHYaGqCSXVAqQ==" - }, - "Microsoft.EntityFrameworkCore.Relational": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "7fhWuSfrCYlv/hvOX5OhbFJF/G9f8sifqTrJiYnAYLDOvNizwv7t9tFPD8JwaF3zM2S54O5/Vni2NxvwzSaW2w==", - "dependencies": { - "Microsoft.EntityFrameworkCore": "3.1.9" - } - }, - "Microsoft.EntityFrameworkCore.Sqlite": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "sMFCWv/1UcsFQZeGQcbfPbEZKZ1oKZqWZXTbc7PEZVMIXu82nbavstdNQ84x5IBXJkxl8iW3zjChb/FRBr5uLQ==", - "dependencies": { - "Microsoft.EntityFrameworkCore.Sqlite.Core": "3.1.9", - "SQLitePCLRaw.bundle_e_sqlite3": "2.0.2" - } - }, - "Microsoft.EntityFrameworkCore.Sqlite.Core": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "Da6h8LdpJwKc1az9DMWt2Mt6gHXPRZqwiumV1Zx0AuM3EThyokVDzBGy2sti0AcBhcQMLJHPEr5R9xuiWvaYYQ==", - "dependencies": { - "Microsoft.Data.Sqlite.Core": "3.1.9", - "Microsoft.DotNet.PlatformAbstractions": "3.1.6", - "Microsoft.EntityFrameworkCore.Relational": "3.1.9", - "Microsoft.Extensions.DependencyModel": "3.1.6" - } - }, - "Microsoft.Extensions.ApiDescription.Server": { - "type": "Transitive", - "resolved": "3.0.0", - "contentHash": "LH4OE/76F6sOCslif7+Xh3fS/wUUrE5ryeXAMcoCnuwOQGT5Smw0p57IgDh/pHgHaGz/e+AmEQb7pRgb++wt0w==" - }, - "Microsoft.Extensions.Caching.Abstractions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "/2QsPAsUZD4qvftZkUKHRRRryPDXWh606/iNXPLrulwHLMr9JNsKBJWVqylT3qU92nJok5VoqSblkY9mSyxFyg==", - "dependencies": { - "Microsoft.Extensions.Primitives": "3.1.9" - } - }, - "Microsoft.Extensions.Caching.Memory": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "/JrVMVetX/kpJQUIlJ6NLQ3zbF0yyryXpo4+uFCqYIUZzgmWk8DS/zSKcyj1tQ3410+vhDEAPngxC+hg0IlJeg==", - "dependencies": { - "Microsoft.Extensions.Caching.Abstractions": "3.1.9", - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.9", - "Microsoft.Extensions.Logging.Abstractions": "3.1.9", - "Microsoft.Extensions.Options": "3.1.9" - } - }, - "Microsoft.Extensions.Configuration": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "lqdkOGNeTMKG981Q7yWGlRiFbIlsRwTlMMiybT+WOzUCFBS/wc25tZgh7Wm/uRoBbWefgvokzmnea7ZjmFedmA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "3.1.9" - } - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "vOJxPKczaHpXeZFrxARxYwsEulhEouXc5aZGgMdkhV/iEXX9/pfjqKk76rTG+4CsJjHV+G/4eMhvOIaQMHENNA==", - "dependencies": { - "Microsoft.Extensions.Primitives": "3.1.9" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "BG6HcT7tARYakftqfQu+cLksgIWG1NdxMY+igI12hdZrUK+WjS973NiRyuao/U9yyTeM9NPwRnC61hCmG3G3jg==", - "dependencies": { - "Microsoft.Extensions.Configuration": "3.1.9" - } - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "ORqfrAACcvTInie1oGola5uky344/PiNfgayTPuZWV4WnSfIQZJQm/ZLpGshJE3h7TqwYaYElGazK/yaM2bFLA==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.9" - } - }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "8PkcaPwiTPOhqshoY4+rQUbz86X6YpLDLUqXOezh7L2A3pgpBmeBBByYIffofBlvQxDdQ0zB2DkWjbZWyCxRWg==" - }, - "Microsoft.Extensions.DependencyModel": { - "type": "Transitive", - "resolved": "3.1.6", - "contentHash": "/UlDKULIVkLQYn1BaHcy/rc91ApDxJb7T75HcCbGdqwvxhnRQRKM2di1E70iCPMF9zsr6f4EgQTotBGxFIfXmw==", - "dependencies": { - "System.Text.Json": "4.7.2" - } - }, - "Microsoft.Extensions.FileProviders.Abstractions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "Q4SGwEFZKiZbpzPgdGbQUULxtcH1zXMOwCPKSm6QwVcOCGshf3QLfBh+O/GyFH4B0RfZ16nKyeW1mMONlRyjUw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "3.1.9" - } - }, - "Microsoft.Extensions.FileProviders.Embedded": { - "type": "Transitive", - "resolved": "1.0.1", - "contentHash": "nSEa8bH3fVdTYGqK4twOKLxxgKIW3cz9g9mrzhPh/CmdvGJWKRTIlBIZi7lz+lqNQpxean5vbAo84R/mU+JpGA==", - "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "1.0.1", - "System.Runtime.Extensions": "4.1.0" - } - }, - "Microsoft.Extensions.FileProviders.Physical": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "HWDSsblTCQp7EEJJmnLzttIhFGzDu+DGqBbOvGCdFT0+pkCuBkn3EiWpEEcm5WMTO5njmsbLSK9ZuUUf2zPsFg==", - "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "3.1.9", - "Microsoft.Extensions.FileSystemGlobbing": "3.1.9" - } - }, - "Microsoft.Extensions.FileSystemGlobbing": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "5bnewG1aBiSESPNwcXGIxDDRN95uqdy+fqZZ8Z63Et5rRNlAwAfXHOrg+FTht7UjHobjvtjzquMCbAWhWEPHIw==" - }, - "Microsoft.Extensions.Logging": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "+V3i0jCQCO6IIOf6e+fL0SqrZd2x/Krug9EEL1JHa9R03RsbEpltCtjVY5hxedyuyuQKwvLoR12sCfu/9XEUAw==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "3.1.9", - "Microsoft.Extensions.DependencyInjection": "3.1.9", - "Microsoft.Extensions.Logging.Abstractions": "3.1.9", - "Microsoft.Extensions.Options": "3.1.9" - } - }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "W5fbF8qVR9SMVVJqDQLIR7meWbev6Pu/lbrm7LDNr4Sp7HOotr4k2UULTdFSXOi5aoDdkQZpWnq0ZSpjrR3tjg==" - }, - "Microsoft.Extensions.Logging.Configuration": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "hv6XsGgikrbkolBJdF1usl9R/nrliC5mifMqHMEY9zWcCLwNkXMJiS8p0lbosrnpVAMi4PbNx39DB51Dqscd0w==", - "dependencies": { - "Microsoft.Extensions.Logging": "3.1.9", - "Microsoft.Extensions.Options.ConfigurationExtensions": "3.1.9" - } - }, - "Microsoft.Extensions.Logging.Console": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "8Dusl1rkDivmvLrwj6QAo917xMHPiDBzG3IG3agiyDdtsC/fRp+1VN5iIN+O09PtEaMged2OLA6wCDwfSTSTZw==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "3.1.9", - "Microsoft.Extensions.Logging": "3.1.9", - "Microsoft.Extensions.Logging.Configuration": "3.1.9" - } - }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "1.0.1", - "contentHash": "pJMOnxuqmG37OjccfvtqVoo3bQGoN+0EJUzzp7+2uxSdioER82caAk6Yi/z5aysapn5XENNIIa7SaYnYKSS69A==", - "dependencies": { - "System.Diagnostics.Debug": "4.0.11", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "Microsoft.Extensions.Options": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "EIb3G1DL+Rl9MvJR7LjI1wCy2nfTN4y8MflbOftn1HLYQBj/Rwl8kUbGTrSFE01c99Wm4ETjWVsjqKcpFvhPng==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.9", - "Microsoft.Extensions.Primitives": "3.1.9" - } - }, - "Microsoft.Extensions.Options.ConfigurationExtensions": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "u5jh7RW+Ev81YqK1ZoBG0lftp2MA9xqXiTiRL46XzaPj2ScNUyiVbzcVY0fPbE27UOpT2hj+yPzRSOMIIo55UA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "3.1.9", - "Microsoft.Extensions.Configuration.Binder": "3.1.9", - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.9", - "Microsoft.Extensions.Options": "3.1.9" - } - }, - "Microsoft.Extensions.PlatformAbstractions": { - "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "zyjUzrOmuevOAJpIo3Mt5GmpALVYCVdLZ99keMbmCxxgQH7oxzU58kGHzE6hAgYEiWsdfMJLjVR7r+vSmaJmtg==", - "dependencies": { - "System.AppContext": "4.1.0", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0" - } - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "3.1.9", - "contentHash": "IrHecH0eGG7/XoeEtv++oLg/sJHRNyeCqlA9RhAo6ig4GpOTjtDr32sBMYuuLtUq8ALahneWkrOzoBAwJ4L4iA==" - }, - "Microsoft.Extensions.WebEncoders": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "TClNvczWRxF6bVPhn5EK3Y3QNi5jTP68Qur+5Fk+MQLPeBI18WN7X145DDJ6bFeNOwgdCHl73lHs5uZp9ish1A==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.2", - "Microsoft.Extensions.Options": "1.0.2", - "System.Text.Encodings.Web": "4.0.1" - } - }, - "Microsoft.IdentityModel.JsonWebTokens": { - "type": "Transitive", - "resolved": "6.8.0", - "contentHash": "+7JIww64PkMt7NWFxoe4Y/joeF7TAtA/fQ0b2GFGcagzB59sKkTt/sMZWR6aSZht5YC7SdHi3W6yM1yylRGJCQ==", - "dependencies": { - "Microsoft.IdentityModel.Tokens": "6.8.0" - } - }, - "Microsoft.IdentityModel.Logging": { - "type": "Transitive", - "resolved": "6.8.0", - "contentHash": "Rfh/p4MaN4gkmhPxwbu8IjrmoDncGfHHPh1sTnc0AcM/Oc39/fzC9doKNWvUAjzFb8LqA6lgZyblTrIsX/wDXg==" - }, - "Microsoft.IdentityModel.Tokens": { - "type": "Transitive", - "resolved": "6.8.0", - "contentHash": "gTqzsGcmD13HgtNePPcuVHZ/NXWmyV+InJgalW/FhWpII1D7V1k0obIseGlWMeA4G+tZfeGMfXr0klnWbMR/mQ==", - "dependencies": { - "Microsoft.CSharp": "4.5.0", - "Microsoft.IdentityModel.Logging": "6.8.0", - "System.Security.Cryptography.Cng": "4.5.0" - } - }, - "Microsoft.Net.Http.Headers": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "2F8USh4hR5xppvaxtw2EStX74Ih+HhRj7aQD1uaB9JmTGy478F7t4VU+IdZXauEDrvS7LYAyyhmOExsUFK3PAw==", - "dependencies": { - "System.Buffers": "4.0.0", - "System.Collections": "4.0.11", - "System.Diagnostics.Contracts": "4.0.1", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Text.Encoding": "4.0.11" - } - }, - "Microsoft.NetCore.Analyzers": { - "type": "Transitive", - "resolved": "3.3.0", - "contentHash": "6qptTHUu1Wfszuf83NhU0IoAb4j7YWOpJs6oc6S4G/nI6aGGWKH/Xi5Vs9L/8lrI74ijEEzPcIwafSQW5ASHtA==" - }, - "Microsoft.NETCore.Platforms": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" - }, - "Microsoft.NETCore.Targets": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" - }, - "Microsoft.NetFramework.Analyzers": { - "type": "Transitive", - "resolved": "3.3.0", - "contentHash": "JTfMic5fEFWICePbr7GXOGPranqS9Qxu2U/BZEcnnGbK1SFW8TxRyGp6O1L52xsbfOdqmzjc0t5ubhDrjj+Xpg==" - }, - "Microsoft.TestPlatform.ObjectModel": { - "type": "Transitive", - "resolved": "16.7.1", - "contentHash": "FL+VpAC/nCCzj80MwX6L8gJD06u2m1SKcQQLAymDLFqNtgtI9h3J5n0mVN+s18qcMzybsmO9GK7rMuHYx11KMg==", - "dependencies": { - "NuGet.Frameworks": "5.0.0" - } - }, - "Microsoft.TestPlatform.TestHost": { - "type": "Transitive", - "resolved": "16.7.1", - "contentHash": "mv7MnBDtqwQAjoH+AphE+Tu0dsF6x/c7Zs8umkb2McbvNALJdfBuWJQbiXGWqhNq7k8eMmnkNO6klJz4pkgekw==", - "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "16.7.1", - "Newtonsoft.Json": "9.0.1" - } - }, - "Microsoft.Win32.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "Namotion.Reflection": { - "type": "Transitive", - "resolved": "1.0.14", - "contentHash": "wuJGiFvGfehH2w7jAhMbCJt0/rvUuHyqSZn0sMhNTviDfBZRyX8LFlR/ndQcofkGWulPDfH5nKYTeGXE8xBHPA==", - "dependencies": { - "Microsoft.CSharp": "4.3.0" - } - }, - "NETStandard.Library": { - "type": "Transitive", - "resolved": "1.6.1", - "contentHash": "WcSp3+vP+yHNgS8EV5J7pZ9IRpeDuARBPN28by8zqff1wJQXm26PVU8L3/fYLBJVU7BtDyqNVWq2KlCVvSSR4A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "System.AppContext": "4.3.0", - "System.Collections": "4.3.0", - "System.Collections.Concurrent": "4.3.0", - "System.Console": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tools": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Calendars": "4.3.0", - "System.IO": "4.3.0", - "System.IO.Compression": "4.3.0", - "System.IO.Compression.ZipFile": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Linq": "4.3.0", - "System.Linq.Expressions": "4.3.0", - "System.Net.Http": "4.3.0", - "System.Net.Primitives": "4.3.0", - "System.Net.Sockets": "4.3.0", - "System.ObjectModel": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Security.Cryptography.X509Certificates": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encoding.Extensions": "4.3.0", - "System.Text.RegularExpressions": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "System.Threading.Timer": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0", - "System.Xml.XDocument": "4.3.0" - } - }, - "Newtonsoft.Json": { - "type": "Transitive", - "resolved": "12.0.2", - "contentHash": "rTK0s2EKlfHsQsH6Yx2smvcTCeyoDNgCW7FEYyV01drPlh2T243PR2DiDXqtC5N4GDm4Ma/lkxfW5a/4793vbA==" - }, - "Newtonsoft.Json.Bson": { - "type": "Transitive", - "resolved": "1.0.1", - "contentHash": "5PYT/IqQ+UK31AmZiSS102R6EsTo+LGTSI8bp7WAUqDKaF4wHXD8U9u4WxTI1vc64tYi++8p3dk3WWNqPFgldw==", - "dependencies": { - "NETStandard.Library": "1.6.1", - "Newtonsoft.Json": "10.0.1" - } - }, - "NJsonSchema": { - "type": "Transitive", - "resolved": "10.2.1", - "contentHash": "/BtWbYTusyoSgQkCB4eYijMfZotB/rfASDsl1k9evlkm5vlOP4s4Y09TOzBChU77d/qUABVYL1Xf+TB8E0Wfpw==", - "dependencies": { - "Namotion.Reflection": "1.0.14", - "Newtonsoft.Json": "9.0.1" - } - }, - "NSwag.Annotations": { - "type": "Transitive", - "resolved": "13.8.2", - "contentHash": "/GO+35CjPYQTPS5/Q8udM5JAMEWVo8JsrkV2Uw3OW4/AJU9iOS7t6WJid6ZlkpLMjnW7oex9mvJ2EZNE4eOG/Q==" - }, - "NSwag.AspNetCore": { - "type": "Transitive", - "resolved": "13.8.2", - "contentHash": "SNGlVSZoMyywBWueZBxl3B/nfaIM0fAcuNhTD/cfMKUn3Cn/Oi8d45HZY5vAPqczvppTbk4cZXyVwWDOfgiPbA==", - "dependencies": { - "Microsoft.AspNetCore.Mvc.Core": "1.0.4", - "Microsoft.AspNetCore.Mvc.Formatters.Json": "1.0.4", - "Microsoft.AspNetCore.StaticFiles": "1.0.4", - "Microsoft.Extensions.ApiDescription.Server": "3.0.0", - "Microsoft.Extensions.FileProviders.Embedded": "1.0.1", - "NSwag.Annotations": "13.8.2", - "NSwag.Core": "13.8.2", - "NSwag.Generation": "13.8.2", - "NSwag.Generation.AspNetCore": "13.8.2", - "System.IO.FileSystem": "4.3.0", - "System.Xml.XPath.XDocument": "4.0.1" - } - }, - "NSwag.Core": { - "type": "Transitive", - "resolved": "13.8.2", - "contentHash": "Hm6pU9qFJuXLo3b27+JTXztfeuI/15Ob1sDsfUu4rchN0+bMogtn8Lia8KVbcalw/M+hXc0rWTFp5ueP23e+iA==", - "dependencies": { - "NJsonSchema": "10.2.1", - "Newtonsoft.Json": "9.0.1" - } - }, - "NSwag.Generation": { - "type": "Transitive", - "resolved": "13.8.2", - "contentHash": "LBIrpHFRZeMMbqL1hdyGb7r8v+T52aOCARxwfAmzE+MlOHVpjsIxyNSXht9EzBFMbSH0tj7CK2Ugo7bm+zUssg==", - "dependencies": { - "NJsonSchema": "10.2.1", - "NSwag.Core": "13.8.2", - "Newtonsoft.Json": "9.0.1" - } - }, - "NSwag.Generation.AspNetCore": { - "type": "Transitive", - "resolved": "13.8.2", - "contentHash": "0ydVv6OidspZ/MS6qmU8hswGtXwq5YZPg+2a2PHGD6jNp2Fef4j1wC3xa3hplDAq7cK+BgpyDKtvj9+X01+P5g==", - "dependencies": { - "Microsoft.AspNetCore.Mvc.ApiExplorer": "1.0.4", - "Microsoft.AspNetCore.Mvc.Core": "1.0.4", - "Microsoft.AspNetCore.Mvc.Formatters.Json": "1.0.4", - "NJsonSchema": "10.2.1", - "NSwag.Generation": "13.8.2" - } - }, - "NuGet.Frameworks": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA==" - }, - "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HdSSp5MnJSsg08KMfZThpuLPJpPwE5hBXvHwoKWosyHHfe8Mh5WKT0ylEOf6yNzX6Ngjxe4Whkafh5q7Ymac4Q==" - }, - "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "+yH1a49wJMy8Zt4yx5RhJrxO/DBDByAiCzNwiETI+1S4mPdCu0OY4djdciC7Vssk0l22wQaDLrXxXkp+3+7bVA==" - }, - "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "c3YNH1GQJbfIPJeCnr4avseugSqPrxwIqzthYyZDN6EuOyNOzq+y2KSUfRcXauya1sF4foESTgwM5e1A8arAKw==" - }, - "runtime.native.System": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.IO.Compression": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.Net.Http": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.Security.Cryptography.Apple": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", - "dependencies": { - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" - } - }, - "runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "NS1U+700m4KFRHR5o4vo9DSlTmlCKu/u7dtE5sUHVIPB+xpXxYQvgBgA6wEIeCz6Yfn0Z52/72WYsToCEPJnrw==", - "dependencies": { - "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "b3pthNgxxFcD+Pc0WSEoC0+md3MyhRS6aCEeenvNE3Fdw1HyJ18ZhRFVJJzIeR/O/jpxPboB805Ho0T3Ul7w8A==" - }, - "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "KeLz4HClKf+nFS7p/6Fi/CqyLXh81FpiGzcmuS8DGi9lUqSnZ6Es23/gv2O+1XVGfrbNmviF7CckBpavkBoIFQ==" - }, - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" - }, - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "X7IdhILzr4ROXd8mI1BUCQMSHSQwelUlBjF1JyTKCjXaOGn2fB4EKBxQbCK2VjO3WaWIdlXZL3W6TiIVnrhX4g==" - }, - "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "nyFNiCk/r+VOiIqreLix8yN+q3Wga9+SE8BCgkf+2BwEKiNx6DyvFjCgkfV743/grxv8jHJ8gUK4XEQw7yzRYg==" - }, - "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ytoewC6wGorL7KoCAvRfsgoJPJbNq+64k2SqW6JcOAebWsFUvCCYgfzQMrnpvPiEl4OrblUlhF2ji+Q1+SVLrQ==" - }, - "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I8bKw2I8k58Wx7fMKQJn2R8lamboCAiHfHeV/pS65ScKWMMI0+wJkLYlEKvgW1D/XvSl/221clBoR2q9QNNM7A==" - }, - "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VB5cn/7OzUfzdnC8tqAIMQciVLiq2epm2NrAm1E9OjNRyG4lVhfR61SMcLizejzQP8R8Uf/0l5qOIbUEi+RdEg==" - }, - "SixLabors.ImageSharp": { - "type": "Transitive", - "resolved": "1.0.1", - "contentHash": "DjLoFNdUfsDP7RhPpr5hcUhl1XiejqBML9uDWuOUwCkc0Y+sG9IJLLbqSOi9XeoWqPviwdcDm1F8nKdF0qTYIQ==" - }, - "SQLitePCLRaw.bundle_e_sqlite3": { - "type": "Transitive", - "resolved": "2.0.2", - "contentHash": "OVPI/nh5AqfLCIKhAYqjCa6AHhc7oKApGcGM3UhMRSerFiBx58nSpGwxVFdMgjOCWZR+fA49nzsnKlWp5hFo8w==", - "dependencies": { - "SQLitePCLRaw.core": "2.0.2", - "SQLitePCLRaw.lib.e_sqlite3": "2.0.2", - "SQLitePCLRaw.provider.dynamic_cdecl": "2.0.2" - } - }, - "SQLitePCLRaw.core": { - "type": "Transitive", - "resolved": "2.0.2", - "contentHash": "TFSBX426OelS1tkaVC254NVVlrJIe9YLhWPkEvuqJj2104QpmDmEYOhfdfDJD1E/2SmqDhoRw1ek5cQHj8olcQ==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Transitive", - "resolved": "2.0.2", - "contentHash": "S+Tsqe/M7wsc+9HeediI6UHtBKf2X586aRwhi1aBVLGe0WxkAo52O9ZxwEy/v8XMLefcrEMupd2e9CDlIT6QCw==" - }, - "SQLitePCLRaw.provider.dynamic_cdecl": { - "type": "Transitive", - "resolved": "2.0.2", - "contentHash": "ZSwacbKJUsxJEZxwT23uZVrGbaIvXcADZDz5Sr66fikO5eehdcceDncjzwzTzWfW13di8gpTpstx3WJSt/Ci5Q==", - "dependencies": { - "SQLitePCLRaw.core": "2.0.2" - } - }, - "System.AppContext": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "fKC+rmaLfeIzUhagxY17Q9siv/sPrjjKcfNg1Ic8IlQkZLipo8ljcaZQu4VtI4Jqbzjc2VTjzGLF6WmsRXAEgA==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ratu44uTIHgeBeI0dE8DWvmXVBSo4u7ozRZZHOMmK/JPpYyo0dAfgSiHlpiObMQ5lEtEyIXA40sKRYg5J6A8uQ==", - "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Collections": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Collections.Concurrent": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Collections.Immutable": { - "type": "Transitive", - "resolved": "1.7.1", - "contentHash": "B43Zsz5EfMwyEbnObwRxW5u85fzJma3lrDeGcSAV1qkhSRTNY5uXAByTn9h9ddNdhM+4/YoLc/CI43umjwIl9Q==" - }, - "System.Collections.NonGeneric": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==", - "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Collections.Specialized": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "Epx8PoVZR0iuOnJJDzp7pWvdfMMOAvpUo95pC4ScH2mJuXkKA2Y4aR3cG9qt2klHgSons1WFh4kcGW7cSXvrxg==", - "dependencies": { - "System.Collections.NonGeneric": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Extensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.ComponentModel": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VyGn1jGRZVfxnh8EdvDCi71v3bMXrsu8aYJOwoV7SNDLVhiEqwP86pPMyRGsDsxhXAm2b3o9OIqeETfN5qfezw==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.ComponentModel.Annotations": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "0YFqjhp/mYkDGpU0Ye1GjE53HMp9UVfGN7seGpAMttAC0C40v5gw598jCgpbBLMmCo0E5YRLBv5Z2doypO49ZQ==" - }, - "System.ComponentModel.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "j8GUkCpM8V4d4vhLIIoBLGey2Z5bCkMVNjEZseyAlm4n5arcsJOeI3zkUP+zvZgzsbLTYh4lYeP/ZD/gdIAPrw==", - "dependencies": { - "System.ComponentModel": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.ComponentModel.TypeConverter": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "16pQ6P+EdhcXzPiEK4kbA953Fu0MNG2ovxTZU81/qsCd1zPRsKc3uif5NgvllCY598k6bI0KUyKW8fanlfaDQg==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Collections.NonGeneric": "4.3.0", - "System.Collections.Specialized": "4.3.0", - "System.ComponentModel": "4.3.0", - "System.ComponentModel.Primitives": "4.3.0", - "System.Globalization": "4.3.0", - "System.Linq": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Configuration.ConfigurationManager": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "gWwQv/Ug1qWJmHCmN17nAbxJYmQBM/E94QxKLksvUiiKB1Ld3Sc/eK1lgmbSjDFxkQhVuayI/cGFZhpBSodLrg==", - "dependencies": { - "System.Security.Cryptography.ProtectedData": "4.4.0" - } - }, - "System.Console": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "DHDrIxiqk1h03m6khKWV2X8p/uvN79rgSqpilL6uzpmSfxfU5ng8VcPtW4qsDsQDHiTv6IPV9TmD5M/vElPNLg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0" - } - }, - "System.Diagnostics.Contracts": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "HvQQjy712vnlpPxaloZYkuE78Gn353L0SJLJVeLcNASeg9c4qla2a1Xq8I7B3jZoDzKPtHTkyVO7AZ5tpeQGuA==", - "dependencies": { - "System.Runtime": "4.1.0" - } - }, - "System.Diagnostics.Debug": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Diagnostics.DiagnosticSource": { - "type": "Transitive", - "resolved": "4.7.1", - "contentHash": "j81Lovt90PDAq8kLpaJfJKV/rWdWuEk6jfV+MBkee33vzYLEUsy4gXK8laa9V2nZlLM9VM9yA/OOQxxPEJKAMw==" - }, - "System.Diagnostics.Tools": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "UUvkJfSYJMM6x527dJg2VyWPSRqIVB0Z7dbjHst1zmwTXz5CcXSYJFWRpuigfbO1Lf7yfZiIaEUesfnl/g5EyA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Diagnostics.TraceSource": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VnYp1NxGx8Ww731y2LJ1vpfb/DKVNKEZ8Jsh5SgQTZREL/YpWRArgh9pI8CDLmgHspZmLL697CaLvH85qQpRiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "runtime.native.System": "4.3.0" - } - }, - "System.Diagnostics.Tracing": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Dynamic.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "SNVi1E/vfWUAs/WYKhE9+qlS6KqK0YVhnlT0HQtr8pMIA8YX3lwy3uPMownDwdYISBdmAF/2holEIldVp85Wag==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Linq": "4.3.0", - "System.Linq.Expressions": "4.3.0", - "System.ObjectModel": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Globalization": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Globalization.Calendars": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Globalization.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.InteropServices": "4.3.0" - } - }, - "System.IdentityModel.Tokens.Jwt": { - "type": "Transitive", - "resolved": "6.8.0", - "contentHash": "5tBCjAub2Bhd5qmcd0WhR5s354e4oLYa//kOWrkX+6/7ZbDDJjMTfwLSOiZ/MMpWdE4DWPLOfTLOq/juj9CKzA==", - "dependencies": { - "Microsoft.IdentityModel.JsonWebTokens": "6.8.0", - "Microsoft.IdentityModel.Tokens": "6.8.0" - } - }, - "System.IO": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.IO.Compression": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Buffers": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "runtime.native.System": "4.3.0", - "runtime.native.System.IO.Compression": "4.3.0" - } - }, - "System.IO.Compression.ZipFile": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "G4HwjEsgIwy3JFBduZ9quBkAu+eUwjIdJleuNSgmUojbH6O3mlvEIme+GHx/cLlTAPcrnnL7GqvB9pTlWRfhOg==", - "dependencies": { - "System.Buffers": "4.3.0", - "System.IO": "4.3.0", - "System.IO.Compression": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Text.Encoding": "4.3.0" - } - }, - "System.IO.FileSystem": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.IO.FileSystem.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.IO.Pipelines": { - "type": "Transitive", - "resolved": "4.7.3", - "contentHash": "zykThu9scJyg2Yeg27GMZCbjzniIsmjtNP5x6kQCd/8rEeKXRy20fP2NOMS7xQ+0pS/E85LZQA+K1aoQLxiUdw==" - }, - "System.Linq": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0" - } - }, - "System.Linq.Expressions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Linq": "4.3.0", - "System.ObjectModel": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Emit.Lightweight": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.3", - "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" - }, - "System.Net.Http": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "sYg+FtILtRQuYWSIAuNOELwVuVsxVyJGWQyOnlAzhV4xvhyFnON1bAzYYC+jjRW8JREM45R0R5Dgi8MTC5sEwA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.DiagnosticSource": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Extensions": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.Net.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.OpenSsl": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Security.Cryptography.X509Certificates": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "runtime.native.System": "4.3.0", - "runtime.native.System.Net.Http": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Net.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.Net.Sockets": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "m6icV6TqQOAdgt5N/9I5KNpjom/5NFtkmGseEH+AK/hny8XrytLH3+b5M8zL/Ycg3fhIocFpUMyl/wpFnVRvdw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Net.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Net.WebSockets": { - "type": "Transitive", - "resolved": "4.0.0", - "contentHash": "2KJo8hir6Edi9jnMDAMhiJoI691xRBmKcbNpwjrvpIMOCTYOtBpSsSEGBxBDV7PKbasJNaFp1+PZz1D7xS41Hg==", - "dependencies": { - "Microsoft.Win32.Primitives": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Threading.Tasks": "4.0.11" - } - }, - "System.ObjectModel": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Reflection": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "VR4kk8XLKebQ4MZuKuIni/7oh+QGFmZW3qORd1GvBq/8026OpW501SzT/oypwiQl4TvT8ErnReh/NzY9u+C6wQ==" - }, - "System.Reflection.Emit.ILGeneration": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit.Lightweight": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.TypeExtensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Resources.ResourceManager": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "System.Runtime.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.Handles": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.InteropServices": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.Runtime.InteropServices.RuntimeInformation": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Threading": "4.3.0", - "runtime.native.System": "4.3.0" - } - }, - "System.Runtime.Numerics": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", - "dependencies": { - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0" - } - }, - "System.Runtime.Serialization.Primitives": { - "type": "Transitive", - "resolved": "4.1.1", - "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", - "dependencies": { - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Security.Claims": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "4Jlp0OgJLS/Voj1kyFP6MJlIYp3crgfH8kNQk2p7+4JYfc1aAmh9PZyAMMbDhuoolGNtux9HqSOazsioRiDvCw==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Security.Principal": "4.0.1" - } - }, - "System.Security.Cryptography.Algorithms": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.Apple": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.Cng": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "WG3r7EyjUe9CMPFSs6bty5doUqT+q9pbI80hlNzo2SkPkZ4VTuZkGWjpp77JB8+uaL4DFPRdBsAY+DX3dBK92A==" - }, - "System.Security.Cryptography.Csp": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Security.Cryptography.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Collections.Concurrent": "4.3.0", - "System.Linq": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", - "dependencies": { - "System.Collections": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", - "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Security.Cryptography.ProtectedData": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==" - }, - "System.Security.Cryptography.X509Certificates": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Calendars": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Cng": "4.3.0", - "System.Security.Cryptography.Csp": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.OpenSsl": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "runtime.native.System": "4.3.0", - "runtime.native.System.Net.Http": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "On+SKhXY5rzxh/S8wlH1Rm0ogBlu7zyHNxeNBiXauNrhHRXAe9EuX8Yl5IOzLPGU5Z4kLWHMvORDOCG8iu9hww==", - "dependencies": { - "System.Runtime": "4.1.0" - } - }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Text.Encoding.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0" - } - }, - "System.Text.Encodings.Web": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "GgJDO6/1bW6kkttxIiPK2jsqllQ3ifaeeBAJJrcoJq0lAclIZsAZZdEqi6JHq+QLZXL2UsjyWb8K8EOH7nOSPw==", - "dependencies": { - "System.Diagnostics.Debug": "4.0.11", - "System.IO": "4.1.0", - "System.Reflection": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "System.Text.Json": { - "type": "Transitive", - "resolved": "4.7.2", - "contentHash": "TcMd95wcrubm9nHvJEQs70rC0H/8omiSGGpU4FQ/ZA1URIqD4pjmFJh2Mfv1yH1eHgJDWTi2hMDXwTET+zOOyg==" - }, - "System.Text.RegularExpressions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.Threading": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", - "dependencies": { - "System.Runtime": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Threading.Tasks": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Threading.Tasks.Extensions": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "WSKUTtLhPR8gllzIWO2x6l4lmAIfbyMAiTlyXAis4QBDonXK4b4S6F8zGARX4/P8wH3DH+sLdhamCiHn+fTU1A==" - }, - "System.Threading.Timer": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "Z6YfyYTCg7lOZjJzBjONJTFKGN9/NIYKSxhU5GRd+DTwHSZyvWp1xuI5aR+dLg+ayyC5Xv57KiY4oJ0tMO89fQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Xml.ReaderWriter": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encoding.Extensions": "4.3.0", - "System.Text.RegularExpressions": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "System.Threading.Tasks.Extensions": "4.3.0" - } - }, - "System.Xml.XDocument": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5zJ0XDxAIg8iy+t4aMnQAu0MqVbqyvfoUVl1yDV61xdo3Vth45oA2FoY4pPkxYAH5f8ixpmTqXeEIya95x0aCQ==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tools": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0" - } - }, - "System.Xml.XmlDocument": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "lJ8AxvkX7GQxpC6GFCeBj8ThYVyQczx2+f/cWHJU8tjS7YfI6Cv6bon70jVEgs2CiFbmmM8b9j1oZVx0dSI2Ww==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0" - } - }, - "System.Xml.XPath": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "UWd1H+1IJ9Wlq5nognZ/XJdyj8qPE4XufBUkAW59ijsCPjZkZe0MUzKKJFBr+ZWBe5Wq1u1d5f2CYgE93uH7DA==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11" - } - }, - "System.Xml.XPath.XDocument": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "FLhdYJx4331oGovQypQ8JIw2kEmNzCsjVOVYY/16kZTUoquZG85oVn7yUhBE2OZt1yGPSXAL0HTEfzjlbNpM7Q==", - "dependencies": { - "System.Diagnostics.Debug": "4.0.11", - "System.Linq": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XDocument": "4.0.11", - "System.Xml.XPath": "4.0.1" - } - }, - "xunit.abstractions": { - "type": "Transitive", - "resolved": "2.0.3", - "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" - }, - "xunit.analyzers": { - "type": "Transitive", - "resolved": "0.10.0", - "contentHash": "4/IDFCJfIeg6bix9apmUtIMwvOsiwqdEexeO/R2D4GReIGPLIRODTpId/l4LRSrAJk9lEO3Zx1H0Zx6uohJDNg==" - }, - "xunit.assert": { - "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "O/Oe0BS5RmSsM+LQOb041TzuPo5MdH2Rov+qXGS37X+KFG1Hxz7kopYklM5+1Y+tRGeXrOx5+Xne1RuqLFQoyQ==", - "dependencies": { - "NETStandard.Library": "1.6.1" - } - }, - "xunit.core": { - "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "Zsj5OMU6JasNGERXZy8s72+pcheG6Q15atS5XpZXqAtULuyQiQ6XNnUsp1gyfC6WgqScqMvySiEHmHcOG6Eg0Q==", - "dependencies": { - "xunit.extensibility.core": "[2.4.1]", - "xunit.extensibility.execution": "[2.4.1]" - } - }, - "xunit.extensibility.core": { - "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "yKZKm/8QNZnBnGZFD9SewkllHBiK0DThybQD/G4PiAmQjKtEZyHi6ET70QPU9KtSMJGRYS6Syk7EyR2EVDU4Kg==", - "dependencies": { - "NETStandard.Library": "1.6.1", - "xunit.abstractions": "2.0.3" - } - }, - "xunit.extensibility.execution": { - "type": "Transitive", - "resolved": "2.4.1", - "contentHash": "7e/1jqBpcb7frLkB6XDrHCGXAbKN4Rtdb88epYxCSRQuZDRW8UtTfdTEVpdTl8s4T56e07hOBVd4G0OdCxIY2A==", - "dependencies": { - "NETStandard.Library": "1.6.1", - "xunit.extensibility.core": "[2.4.1]" - } - }, - "timeline": { - "type": "Project", - "dependencies": { - "AutoMapper": "10.1.1", - "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.1.0", - "Microsoft.AspNetCore.SpaServices.Extensions": "3.1.9", - "Microsoft.EntityFrameworkCore": "3.1.9", - "Microsoft.EntityFrameworkCore.Analyzers": "3.1.9", - "Microsoft.EntityFrameworkCore.Sqlite": "3.1.9", - "NSwag.AspNetCore": "13.8.2", - "SixLabors.ImageSharp": "1.0.1", - "System.IdentityModel.Tokens.Jwt": "6.8.0", - "Timeline.ErrorCodes": "1.0.0" - } - }, - "timeline.errorcodes": { - "type": "Project" - } - } - } -} \ No newline at end of file -- cgit v1.2.3