Remove tests
This commit is contained in:
@@ -1,6 +1,3 @@
|
|||||||
<Solution>
|
<Solution>
|
||||||
<Folder Name="/Tests/">
|
|
||||||
<Project Path="Tests/Musify.WebApi.Tests/Musify.WebApi.Tests.csproj" />
|
|
||||||
</Folder>
|
|
||||||
<Project Path="WebApi/WebApi.csproj" />
|
<Project Path="WebApi/WebApi.csproj" />
|
||||||
</Solution>
|
</Solution>
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
using Ardalis.Result;
|
|
||||||
using FluentAssertions;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Http.HttpResults;
|
|
||||||
using WebApi.Extensions;
|
|
||||||
using Xunit;
|
|
||||||
using IResult = Microsoft.AspNetCore.Http.IResult;
|
|
||||||
|
|
||||||
namespace Musify.WebApi.Tests.Extensions;
|
|
||||||
|
|
||||||
public sealed class ResultHttpExtensionsTests
|
|
||||||
{
|
|
||||||
private static int StatusCodeOf(IResult result) =>
|
|
||||||
((IStatusCodeHttpResult)result).StatusCode ?? 0;
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_Ok_maps_to_204_no_content()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result.Success().ToHttpResult()).Should().Be(StatusCodes.Status204NoContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_NoContent_maps_to_204()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result.NoContent().ToHttpResult()).Should().Be(StatusCodes.Status204NoContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_NotFound_maps_to_404()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result.NotFound("nope").ToHttpResult()).Should().Be(StatusCodes.Status404NotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_Invalid_maps_to_validation_problem_400()
|
|
||||||
{
|
|
||||||
var result = Result.Invalid(new ValidationError("field", "bad")).ToHttpResult();
|
|
||||||
result.Should().BeOfType<ProblemHttpResult>();
|
|
||||||
StatusCodeOf(result).Should().Be(StatusCodes.Status400BadRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_Unauthorized_maps_to_401()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result.Unauthorized().ToHttpResult()).Should().Be(StatusCodes.Status401Unauthorized);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_Forbidden_maps_to_403()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result.Forbidden().ToHttpResult()).Should().Be(StatusCodes.Status403Forbidden);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_Conflict_maps_to_409()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result.Conflict("dup").ToHttpResult()).Should().Be(StatusCodes.Status409Conflict);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Result_Error_maps_to_problem_500()
|
|
||||||
{
|
|
||||||
var result = Result.Error("boom").ToHttpResult();
|
|
||||||
result.Should().BeOfType<ProblemHttpResult>();
|
|
||||||
StatusCodeOf(result).Should().Be(StatusCodes.Status500InternalServerError);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ResultT_Ok_maps_to_200_with_value()
|
|
||||||
{
|
|
||||||
var result = Result<string>.Success("payload").ToHttpResult();
|
|
||||||
result.Should().BeOfType<Ok<string>>();
|
|
||||||
result.As<Ok<string>>().Value.Should().Be("payload");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ResultT_NotFound_maps_to_404()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result<string>.NotFound("nope").ToHttpResult()).Should().Be(StatusCodes.Status404NotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ResultT_Invalid_maps_to_validation_problem_with_grouped_errors()
|
|
||||||
{
|
|
||||||
var result = Result<string>.Invalid(
|
|
||||||
new ValidationError("Name", "required"),
|
|
||||||
new ValidationError("Name", "too short"),
|
|
||||||
new ValidationError("Age", "invalid")).ToHttpResult();
|
|
||||||
|
|
||||||
result.Should().BeOfType<ProblemHttpResult>();
|
|
||||||
var details = result.As<ProblemHttpResult>().ProblemDetails.Should().BeOfType<HttpValidationProblemDetails>().Subject;
|
|
||||||
details.Errors.Should().ContainKey("Name");
|
|
||||||
details.Errors["Name"].Should().BeEquivalentTo("required", "too short");
|
|
||||||
details.Errors.Should().ContainKey("Age");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ResultT_Unauthorized_maps_to_401()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result<string>.Unauthorized().ToHttpResult()).Should().Be(StatusCodes.Status401Unauthorized);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ResultT_Forbidden_maps_to_403()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result<string>.Forbidden().ToHttpResult()).Should().Be(StatusCodes.Status403Forbidden);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ResultT_Conflict_maps_to_409()
|
|
||||||
{
|
|
||||||
StatusCodeOf(Result<string>.Conflict("dup").ToHttpResult()).Should().Be(StatusCodes.Status409Conflict);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ResultT_Error_maps_to_problem_500()
|
|
||||||
{
|
|
||||||
var result = Result<string>.Error("boom").ToHttpResult();
|
|
||||||
result.Should().BeOfType<ProblemHttpResult>();
|
|
||||||
StatusCodeOf(result).Should().Be(StatusCodes.Status500InternalServerError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
using System.Net;
|
|
||||||
using System.Net.Http.Json;
|
|
||||||
using FluentAssertions;
|
|
||||||
using Musify.Application.PlayLists.Responses;
|
|
||||||
using Musify.Application.Users.Responses;
|
|
||||||
using NSubstitute;
|
|
||||||
using WebApi.DataTransferObjects.PlayLists;
|
|
||||||
using WebApi.DataTransferObjects.Tracks;
|
|
||||||
using WebApi.DataTransferObjects.Users;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Musify.WebApi.Tests.Integration;
|
|
||||||
|
|
||||||
public sealed class ApiIntegrationTests(MusifyApiFactory factory)
|
|
||||||
: IClassFixture<MusifyApiFactory>
|
|
||||||
{
|
|
||||||
private sealed record ValidationProblemResponse(Dictionary<string, string[]> Errors);
|
|
||||||
|
|
||||||
private sealed record TrackUploadUrlsLikeResponse(string PictureUploadUrl, string AudioUploadUrl);
|
|
||||||
|
|
||||||
private readonly HttpClient _client = factory.CreateClient();
|
|
||||||
|
|
||||||
private async Task<Guid> CreateUserAsync(string name = "IntegrationUser")
|
|
||||||
{
|
|
||||||
var id = Guid.NewGuid();
|
|
||||||
var response = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(id, name, null, null));
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Create_then_get_user_roundtrips_through_the_real_pipeline()
|
|
||||||
{
|
|
||||||
var id = Guid.NewGuid();
|
|
||||||
|
|
||||||
var create = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(id, "Alice", "Al", "Ice"));
|
|
||||||
create.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
||||||
|
|
||||||
var get = await _client.GetAsync($"/users/{id}");
|
|
||||||
get.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
||||||
UserApplicationResponse user = await get.Content.ReadFromJsonAsync<UserApplicationResponse>()
|
|
||||||
?? throw new InvalidOperationException("The response body was null.");
|
|
||||||
user.Id.Should().Be(id);
|
|
||||||
user.Name.Should().Be("Alice");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Create_user_with_invalid_body_returns_400_validation_problem()
|
|
||||||
{
|
|
||||||
var response = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(Guid.Empty, "", null, null));
|
|
||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
|
||||||
ValidationProblemResponse problem = await response.Content.ReadFromJsonAsync<ValidationProblemResponse>()
|
|
||||||
?? throw new InvalidOperationException("The response body was null.");
|
|
||||||
problem.Errors.Should().ContainKey(nameof(CreateUserRequest.Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Create_duplicate_user_returns_409_conflict()
|
|
||||||
{
|
|
||||||
var id = await CreateUserAsync();
|
|
||||||
|
|
||||||
var duplicate = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(id, "Other", null, null));
|
|
||||||
|
|
||||||
duplicate.StatusCode.Should().Be(HttpStatusCode.Conflict);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_unknown_user_returns_404()
|
|
||||||
{
|
|
||||||
var response = await _client.GetAsync($"/users/{Guid.NewGuid()}");
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Create_playlist_without_picture_returns_201_and_persists()
|
|
||||||
{
|
|
||||||
var userId = await CreateUserAsync();
|
|
||||||
|
|
||||||
var response = await _client.PostAsJsonAsync(
|
|
||||||
$"/playLists/users/{userId}",
|
|
||||||
new CreatePlayListRequest("My Mix", "A description", null));
|
|
||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
||||||
PlayListApplicationResponse playList = await response.Content.ReadFromJsonAsync<PlayListApplicationResponse>()
|
|
||||||
?? throw new InvalidOperationException("The response body was null.");
|
|
||||||
playList.Name.Should().Be("My Mix");
|
|
||||||
|
|
||||||
var get = await _client.GetAsync($"/playLists/{playList.Id}");
|
|
||||||
get.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Create_playlist_for_unknown_user_returns_404()
|
|
||||||
{
|
|
||||||
var response = await _client.PostAsJsonAsync(
|
|
||||||
$"/playLists/users/{Guid.NewGuid()}",
|
|
||||||
new CreatePlayListRequest("Mix", "desc", null));
|
|
||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Create_playlist_with_invalid_body_returns_400()
|
|
||||||
{
|
|
||||||
var userId = await CreateUserAsync();
|
|
||||||
|
|
||||||
var response = await _client.PostAsJsonAsync(
|
|
||||||
$"/playLists/users/{userId}",
|
|
||||||
new CreatePlayListRequest("", "", null));
|
|
||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_unknown_track_returns_404()
|
|
||||||
{
|
|
||||||
var response = await _client.GetAsync($"/tracks/{Guid.NewGuid()}");
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Request_track_upload_urls_issues_presigned_urls()
|
|
||||||
{
|
|
||||||
var userId = await CreateUserAsync();
|
|
||||||
factory.Storage
|
|
||||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<CancellationToken>())
|
|
||||||
.Returns("https://signed.example/put");
|
|
||||||
|
|
||||||
var response = await _client.PostAsJsonAsync(
|
|
||||||
$"/tracks/upload-urls/users/{userId}",
|
|
||||||
new RequestTrackUploadUrlsRequest("png", "image/png", "mp3", "audio/mpeg"));
|
|
||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
||||||
TrackUploadUrlsLikeResponse body = await response.Content.ReadFromJsonAsync<TrackUploadUrlsLikeResponse>()
|
|
||||||
?? throw new InvalidOperationException("The response body was null.");
|
|
||||||
body.PictureUploadUrl.Should().Be("https://signed.example/put");
|
|
||||||
body.AudioUploadUrl.Should().Be("https://signed.example/put");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Testing;
|
|
||||||
using Microsoft.AspNetCore.TestHost;
|
|
||||||
using Microsoft.Data.Sqlite;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Musify.Application.Contracts;
|
|
||||||
using Musify.Application.Tests.Infrastructure;
|
|
||||||
using NSubstitute;
|
|
||||||
|
|
||||||
namespace Musify.WebApi.Tests.Integration;
|
|
||||||
|
|
||||||
public sealed class MusifyApiFactory : WebApplicationFactory<Program>
|
|
||||||
{
|
|
||||||
private readonly SqliteConnection _connection = new("DataSource=:memory:;Foreign Keys=False");
|
|
||||||
|
|
||||||
public IStorageService Storage { get; } = Substitute.For<IStorageService>();
|
|
||||||
public IEventBus EventBus { get; } = Substitute.For<IEventBus>();
|
|
||||||
|
|
||||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
|
||||||
{
|
|
||||||
builder.UseEnvironment("Testing");
|
|
||||||
|
|
||||||
builder.ConfigureAppConfiguration((_, config) =>
|
|
||||||
{
|
|
||||||
config.AddInMemoryCollection(new Dictionary<string, string?>
|
|
||||||
{
|
|
||||||
["Database:ConnectionString"] = "Host=localhost;Database=test;Username=test;Password=test",
|
|
||||||
["ApplicationStorage:Bucket"] = TestData.Bucket,
|
|
||||||
["PlayList:Routes:ParentFolders"] = "PlayLists",
|
|
||||||
["Track:Routes:ParentFolder"] = "Tracks",
|
|
||||||
["UploadIntent:TempRootPrefix"] = "temp",
|
|
||||||
["InfrastructureStorage:Address"] = "http://localhost:9000",
|
|
||||||
["InfrastructureStorage:AccessKey"] = "test",
|
|
||||||
["InfrastructureStorage:SecretAccessKey"] = "test",
|
|
||||||
["InfrastructureStorage:ForcePathStyle"] = "true",
|
|
||||||
["InfrastructureStorage:UseHttp"] = "true",
|
|
||||||
["MassTransit:Address"] = "rabbitmq://localhost",
|
|
||||||
["MassTransit:Username"] = "guest",
|
|
||||||
["MassTransit:Password"] = "guest",
|
|
||||||
["OpenTelemetry:OtlpEndpoint"] = "http://localhost:4317",
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
builder.ConfigureTestServices(services =>
|
|
||||||
{
|
|
||||||
services.RemoveAll<IHostedService>();
|
|
||||||
|
|
||||||
_connection.Open();
|
|
||||||
|
|
||||||
services.RemoveAll<IDatabase>();
|
|
||||||
services.AddScoped<IDatabase>(_ =>
|
|
||||||
{
|
|
||||||
var options = new DbContextOptionsBuilder<TestDatabase>()
|
|
||||||
.UseSqlite(_connection)
|
|
||||||
.Options;
|
|
||||||
var db = new TestDatabase(options);
|
|
||||||
db.Database.EnsureCreated();
|
|
||||||
return db;
|
|
||||||
});
|
|
||||||
|
|
||||||
services.RemoveAll<IStorageService>();
|
|
||||||
services.AddScoped(_ => Storage);
|
|
||||||
|
|
||||||
services.RemoveAll<IEventBus>();
|
|
||||||
services.AddScoped(_ => EventBus);
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
base.Dispose(disposing);
|
|
||||||
if (disposing)
|
|
||||||
_connection.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
<RootNamespace>Musify.WebApi.Tests</RootNamespace>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
|
||||||
<PackageReference Include="xunit" Version="2.9.2" />
|
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="FluentAssertions" Version="6.12.2" />
|
|
||||||
<PackageReference Include="FluentValidation" Version="12.1.1" />
|
|
||||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.8" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.8" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\WebApi\WebApi.csproj" />
|
|
||||||
<ProjectReference Include="..\..\..\MusifyBackend\Tests\Musify.Application.Tests\Musify.Application.Tests.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
using FluentValidation.TestHelper;
|
|
||||||
using WebApi.DataTransferObjects.PlayLists;
|
|
||||||
using WebApi.DataTransferObjects.Tracks;
|
|
||||||
using WebApi.DataTransferObjects.Users;
|
|
||||||
using WebApi.Validators.PlayLists;
|
|
||||||
using WebApi.Validators.Tracks;
|
|
||||||
using WebApi.Validators.Users;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Musify.WebApi.Tests.Validators;
|
|
||||||
|
|
||||||
public sealed class CreateTrackRequestValidatorTests
|
|
||||||
{
|
|
||||||
private readonly CreateTrackRequestValidator _validator = new();
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Valid_request_passes()
|
|
||||||
{
|
|
||||||
var model = new CreateTrackRequest("Song", Guid.NewGuid(), Guid.NewGuid());
|
|
||||||
_validator.TestValidate(model).ShouldNotHaveAnyValidationErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData("")]
|
|
||||||
[InlineData(null)]
|
|
||||||
public void Empty_title_fails(string? title)
|
|
||||||
{
|
|
||||||
var model = new CreateTrackRequest(title!, Guid.NewGuid(), Guid.NewGuid());
|
|
||||||
_validator.TestValidate(model).ShouldHaveValidationErrorFor(x => x.Title);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Title_longer_than_50_fails()
|
|
||||||
{
|
|
||||||
var model = new CreateTrackRequest(new string('a', 51), Guid.NewGuid(), Guid.NewGuid());
|
|
||||||
_validator.TestValidate(model).ShouldHaveValidationErrorFor(x => x.Title);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Empty_intent_ids_fail()
|
|
||||||
{
|
|
||||||
var model = new CreateTrackRequest("Song", Guid.Empty, Guid.Empty);
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.PictureIntentId);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.AudioIntentId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RequestTrackUploadUrlsRequestValidatorTests
|
|
||||||
{
|
|
||||||
private readonly RequestTrackUploadUrlsRequestValidator _validator = new();
|
|
||||||
|
|
||||||
private static RequestTrackUploadUrlsRequest Valid() =>
|
|
||||||
new("png", "image/png", "mp3", "audio/mpeg");
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Valid_request_passes()
|
|
||||||
{
|
|
||||||
_validator.TestValidate(Valid()).ShouldNotHaveAnyValidationErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Missing_required_fields_fail()
|
|
||||||
{
|
|
||||||
var model = new RequestTrackUploadUrlsRequest("", "", "", "");
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.PictureFileType);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.PictureContentType);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.AudioFileType);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.AudioContentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Non_positive_expected_sizes_fail_when_provided()
|
|
||||||
{
|
|
||||||
var model = Valid() with { ExpectedPictureSizeBytes = 0, ExpectedAudioSizeBytes = -1 };
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.ExpectedPictureSizeBytes);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.ExpectedAudioSizeBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Null_expected_sizes_are_allowed()
|
|
||||||
{
|
|
||||||
var model = Valid() with { ExpectedPictureSizeBytes = null, ExpectedAudioSizeBytes = null };
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldNotHaveValidationErrorFor(x => x.ExpectedPictureSizeBytes);
|
|
||||||
result.ShouldNotHaveValidationErrorFor(x => x.ExpectedAudioSizeBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class CreatePlayListRequestValidatorTests
|
|
||||||
{
|
|
||||||
private readonly CreatePlayListRequestValidator _validator = new();
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Valid_request_passes()
|
|
||||||
{
|
|
||||||
var model = new CreatePlayListRequest("My List", "A description", null);
|
|
||||||
_validator.TestValidate(model).ShouldNotHaveAnyValidationErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Empty_name_and_description_fail()
|
|
||||||
{
|
|
||||||
var model = new CreatePlayListRequest("", "", null);
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.Name);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.Description);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Over_length_name_and_description_fail()
|
|
||||||
{
|
|
||||||
var model = new CreatePlayListRequest(new string('n', 51), new string('d', 257), null);
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.Name);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.Description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class UpdatePlayListRequestValidatorTests
|
|
||||||
{
|
|
||||||
private readonly UpdatePlayListRequestValidator _validator = new();
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void All_null_is_valid()
|
|
||||||
{
|
|
||||||
_validator.TestValidate(new UpdatePlayListRequest(null, null, null))
|
|
||||||
.ShouldNotHaveAnyValidationErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Over_length_values_fail_only_when_provided()
|
|
||||||
{
|
|
||||||
var model = new UpdatePlayListRequest(new string('n', 51), new string('d', 257), null);
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.NewName);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.NewDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Empty_string_name_is_allowed_by_length_rule()
|
|
||||||
{
|
|
||||||
var model = new UpdatePlayListRequest("", null, null);
|
|
||||||
_validator.TestValidate(model).ShouldNotHaveValidationErrorFor(x => x.NewName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RequestPlayListPictureUploadRequestValidatorTests
|
|
||||||
{
|
|
||||||
private readonly RequestPlayListPictureUploadRequestValidator _validator = new();
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Valid_request_passes()
|
|
||||||
{
|
|
||||||
_validator.TestValidate(new RequestPlayListPictureUploadRequest("webp", "image/webp"))
|
|
||||||
.ShouldNotHaveAnyValidationErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Missing_filetype_and_contenttype_fail()
|
|
||||||
{
|
|
||||||
var result = _validator.TestValidate(new RequestPlayListPictureUploadRequest("", ""));
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.FileType);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.ContentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Non_positive_size_fails_when_provided()
|
|
||||||
{
|
|
||||||
var result = _validator.TestValidate(new RequestPlayListPictureUploadRequest("webp", "image/webp", 0));
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.ExpectedSizeBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class CreateUserRequestValidatorTests
|
|
||||||
{
|
|
||||||
private readonly CreateUserRequestValidator _validator = new();
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Valid_request_passes()
|
|
||||||
{
|
|
||||||
var model = new CreateUserRequest(Guid.NewGuid(), "Alice", "Al", "Ice");
|
|
||||||
_validator.TestValidate(model).ShouldNotHaveAnyValidationErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Empty_id_and_name_fail()
|
|
||||||
{
|
|
||||||
var model = new CreateUserRequest(Guid.Empty, "", null, null);
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.Id);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Over_length_optional_names_fail_only_when_provided()
|
|
||||||
{
|
|
||||||
var model = new CreateUserRequest(Guid.NewGuid(), "Alice", new string('f', 49), new string('s', 49));
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.FirstName);
|
|
||||||
result.ShouldHaveValidationErrorFor(x => x.SecondName);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Null_optional_names_are_allowed()
|
|
||||||
{
|
|
||||||
var model = new CreateUserRequest(Guid.NewGuid(), "Alice", null, null);
|
|
||||||
var result = _validator.TestValidate(model);
|
|
||||||
result.ShouldNotHaveValidationErrorFor(x => x.FirstName);
|
|
||||||
result.ShouldNotHaveValidationErrorFor(x => x.SecondName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user