Design Prot Merge #1

Merged
NotS1mp merged 217 commits from design-prot into master 2026-09-21 15:48:16 +00:00
73 changed files with 3718 additions and 3645 deletions
Showing only changes of commit b5700614c1 - Show all commits
@@ -3,8 +3,8 @@ using Microsoft.AspNetCore.Http;
using Musify.Api.Authentication;
using Xunit;
namespace Musify.Api.Tests.Authentication;
namespace Musify.Api.Tests.Authentication
{
public sealed class CurrentUserTests
{
private static async Task<CurrentUser> BindAsync(ClaimsPrincipal principal)
@@ -82,3 +82,4 @@ public sealed class CurrentUserTests
Assert.Null(user.FindClaim("missing"));
}
}
}
@@ -6,8 +6,8 @@ using Musify.Api.Tests.TestSupport;
using Musify.Application.Albums.Responses;
using Xunit;
namespace Musify.Api.Tests.Endpoints;
namespace Musify.Api.Tests.Endpoints
{
[Collection(ApiCollection.Name)]
public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
{
@@ -96,3 +96,4 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Api.Tests.TestSupport;
using Musify.Application.Users.Responses;
using Xunit;
namespace Musify.Api.Tests.Endpoints;
namespace Musify.Api.Tests.Endpoints
{
[Collection(ApiCollection.Name)]
public sealed class UserEndpointsTests(ApiTestFixture fixture)
{
@@ -71,3 +71,4 @@ public sealed class UserEndpointsTests(ApiTestFixture fixture)
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
}
}
@@ -4,8 +4,8 @@ using Microsoft.Extensions.DependencyInjection;
using Musify.Api.Extensions;
using Xunit;
namespace Musify.Api.Tests.Extensions;
namespace Musify.Api.Tests.Extensions
{
public sealed class ErrorOrHttpExtensionsTests
{
// The concrete IResult types (NoContent, UnauthorizedHttpResult, ...) resolve logging/problem-
@@ -135,3 +135,4 @@ public sealed class ErrorOrHttpExtensionsTests
Assert.Equal(StatusCodes.Status409Conflict, statusCode);
}
}
}
@@ -6,8 +6,8 @@ using Musify.Api.Filters;
using NSubstitute;
using Xunit;
namespace Musify.Api.Tests.Filters;
namespace Musify.Api.Tests.Filters
{
public sealed class ValidationFilterTests
{
public sealed record Payload(string Name);
@@ -64,3 +64,4 @@ public sealed class ValidationFilterTests
await validator.DidNotReceiveWithAnyArgs().ValidateAsync(Arg.Any<Payload>(), Arg.Any<CancellationToken>());
}
}
}
@@ -11,8 +11,8 @@ using NSubstitute;
using Testcontainers.PostgreSql;
using Xunit;
namespace Musify.Api.Tests.TestSupport;
namespace Musify.Api.Tests.TestSupport
{
/// <summary>
/// Boots the real <c>Musify.Api</c> host — real routing, real auth/authorization pipeline,
/// real validators, real Mediator handlers — against a private Postgres container (so EF
@@ -119,3 +119,4 @@ public sealed class ApiCollection : ICollectionFixture<ApiTestFixture>
{
public const string Name = "Api";
}
}
@@ -4,8 +4,8 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Musify.Api.Tests.TestSupport;
namespace Musify.Api.Tests.TestSupport
{
/// <summary>
/// Replaces the real JwtBearer handler in the test host: a request carrying the
/// <see cref="UserIdHeader"/> header authenticates as that user id, with no real token,
@@ -35,3 +35,4 @@ public sealed class FakeAuthenticationHandler(
return Task.FromResult(AuthenticateResult.Success(ticket));
}
}
}
@@ -2,8 +2,8 @@ using Musify.Api.DataTransferObjects.Albums;
using Musify.Api.Validators.Albums;
using Xunit;
namespace Musify.Api.Tests.Validators;
namespace Musify.Api.Tests.Validators
{
public sealed class CreateAlbumRequestValidatorTests
{
private readonly CreateAlbumRequestValidator validator = new();
@@ -73,3 +73,4 @@ public sealed class CreateAlbumRequestValidatorTests
Assert.False(result.IsValid);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Api.DataTransferObjects.Users;
using Musify.Api.Validators.Users;
using Xunit;
namespace Musify.Api.Tests.Validators;
namespace Musify.Api.Tests.Validators
{
public sealed class CreateUserRequestValidatorTests
{
private readonly CreateUserRequestValidator validator = new();
@@ -49,3 +49,4 @@ public sealed class CreateUserRequestValidatorTests
Assert.True(result.IsValid);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
{
private AddTrackToAlbumCommandHandler CreateHandler() => new(Database, NoOpLogger<AddTrackToAlbumCommandHandler>());
@@ -109,3 +109,4 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
Assert.Equal(4, newLink.TrackNumber);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Albums;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class CreateAlbumCommandHandlerTests : HandlerTestBase
{
private CreateAlbumCommandHandler CreateHandler() => new(Database, NoOpLogger<CreateAlbumCommandHandler>());
@@ -41,3 +41,4 @@ public sealed class CreateAlbumCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Albums;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class DeleteAlbumCommandHandlerTests : HandlerTestBase
{
private DeleteAlbumCommandHandler CreateHandler() => new(Database, NoOpLogger<DeleteAlbumCommandHandler>());
@@ -44,3 +44,4 @@ public sealed class DeleteAlbumCommandHandlerTests : HandlerTestBase
Assert.NotNull(await Database.UserAlbums.FindAsync([album.Id], TestContext.Current.CancellationToken));
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class GetAlbumByIdQueryHandlerTests : HandlerTestBase
{
private GetAlbumByIdQueryHandler CreateHandler() => new(Database);
@@ -34,3 +34,4 @@ public sealed class GetAlbumByIdQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class GetAlbumTracksQueryHandlerTests : HandlerTestBase
{
private GetAlbumTracksQueryHandler CreateHandler() => new(Database);
@@ -36,3 +36,4 @@ public sealed class GetAlbumTracksQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Albums;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class GetAlbumsByUserIdQueryHandlerTests : HandlerTestBase
{
private GetAlbumsByUserIdQueryHandler CreateHandler() => new(Database);
@@ -31,3 +31,4 @@ public sealed class GetAlbumsByUserIdQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.Albums;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class GetAlbumsQueryHandlerTests : HandlerTestBase
{
private GetAlbumsQueryHandler CreateHandler() => new(Database);
@@ -46,3 +46,4 @@ public sealed class GetAlbumsQueryHandlerTests : HandlerTestBase
Assert.True(result.Value.HasNextPage);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class GetRecentlyListenedAlbumsQueryHandlerTests : HandlerTestBase
{
private GetRecentlyListenedAlbumsQueryHandler CreateHandler() => new(Database);
@@ -58,3 +58,4 @@ public sealed class GetRecentlyListenedAlbumsQueryHandlerTests : HandlerTestBase
Assert.Equal(2, result.Value.Count);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class RemoveTrackFromAlbumCommandHandlerTests : HandlerTestBase
{
private RemoveTrackFromAlbumCommandHandler CreateHandler() =>
@@ -70,3 +70,4 @@ public sealed class RemoveTrackFromAlbumCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Albums;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.Albums;
namespace Musify.Application.Tests.Albums
{
public sealed class UpdateAlbumCommandHandlerTests : HandlerTestBase
{
private UpdateAlbumCommandHandler CreateHandler() => new(Database, NoOpLogger<UpdateAlbumCommandHandler>());
@@ -55,3 +55,4 @@ public sealed class UpdateAlbumCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
}
}
@@ -8,8 +8,8 @@ using Musify.Domain.ValueObjects;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Mixes;
namespace Musify.Application.Tests.Mixes
{
public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
{
private readonly IYouTubeMusicService youTubeMusicService = Substitute.For<IYouTubeMusicService>();
@@ -104,3 +104,4 @@ public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
Assert.All(items, item => Assert.Equal(MixItemSource.Musify, item.Source));
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Mixes;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.Mixes;
namespace Musify.Application.Tests.Mixes
{
public sealed class GetMixByIdQueryHandlerTests : HandlerTestBase
{
private GetMixByIdQueryHandler CreateHandler() => new(Database);
@@ -45,3 +45,4 @@ public sealed class GetMixByIdQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.Mixes;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.Mixes;
namespace Musify.Application.Tests.Mixes
{
public sealed class GetMixesByUserIdQueryHandlerTests : HandlerTestBase
{
private GetMixesByUserIdQueryHandler CreateHandler() => new(Database);
@@ -36,3 +36,4 @@ public sealed class GetMixesByUserIdQueryHandlerTests : HandlerTestBase
Assert.Empty(result.Value);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class AddTrackToPlayListCommandHandlerTests : HandlerTestBase
{
private AddTrackToPlayListCommandHandler CreateHandler() => new(Database, NoOpLogger<AddTrackToPlayListCommandHandler>());
@@ -90,3 +90,4 @@ public sealed class AddTrackToPlayListCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
}
}
@@ -8,8 +8,8 @@ using Musify.Domain.Entities;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class AddYouTubeTrackToPlayListCommandHandlerTests : HandlerTestBase
{
private readonly IEventBus eventBus = Substitute.For<IEventBus>();
@@ -102,3 +102,4 @@ public sealed class AddYouTubeTrackToPlayListCommandHandlerTests : HandlerTestBa
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Tests.TestSupport;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class CreatePlayListCommandHandlerTests : HandlerTestBase
{
private readonly IEventBus eventBus = Substitute.For<IEventBus>();
@@ -83,3 +83,4 @@ public sealed class CreatePlayListCommandHandlerTests : HandlerTestBase
Assert.True(result.IsError);
}
}
}
@@ -6,8 +6,8 @@ using Musify.Domain.ValueObjects;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class DeletePlayListCommandHandlerTests : HandlerTestBase
{
private readonly IEventBus eventBus = Substitute.For<IEventBus>();
@@ -51,3 +51,4 @@ public sealed class DeletePlayListCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class GetPlayListByIdQueryHandlerTests : HandlerTestBase
{
private GetPlayListByIdQueryHandler CreateHandler() => new(Database);
@@ -33,3 +33,4 @@ public sealed class GetPlayListByIdQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.PlayLists;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class GetPlayListCoverQueryHandlerTests : HandlerTestBase
{
private GetPlayListCoverQueryHandler CreateHandler() =>
@@ -35,3 +35,4 @@ public sealed class GetPlayListCoverQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class GetPlayListTracksQueryHandlerTests : HandlerTestBase
{
private GetPlayListTracksQueryHandler CreateHandler() => new(Database);
@@ -36,3 +36,4 @@ public sealed class GetPlayListTracksQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.ValueObjects;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class GetPlayListsByUserIdQueryHandlerTests : HandlerTestBase
{
private GetPlayListsByUserIdQueryHandler CreateHandler() => new(Database);
@@ -40,3 +40,4 @@ public sealed class GetPlayListsByUserIdQueryHandlerTests : HandlerTestBase
Assert.Equal("Road Trip", playList.Name);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.PlayLists;
using Musify.Application.Tests.TestSupport;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class GetPlayListsQueryHandlerTests : HandlerTestBase
{
private GetPlayListsQueryHandler CreateHandler() => new(Database);
@@ -29,3 +29,4 @@ public sealed class GetPlayListsQueryHandlerTests : HandlerTestBase
Assert.Empty(result.Value.Items);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class RemoveTrackFromPlayListCommandHandlerTests : HandlerTestBase
{
private RemoveTrackFromPlayListCommandHandler CreateHandler() => new(Database, NoOpLogger<RemoveTrackFromPlayListCommandHandler>());
@@ -57,3 +57,4 @@ public sealed class RemoveTrackFromPlayListCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -8,8 +8,8 @@ using Musify.Application.Tests.TestSupport;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class RequestPlayListPictureUploadCommandHandlerTests : HandlerTestBase
{
private readonly IStorageService storageService = Substitute.For<IStorageService>();
@@ -72,3 +72,4 @@ public sealed class RequestPlayListPictureUploadCommandHandlerTests : HandlerTes
Assert.Empty(await Database.UploadIntents.ToListAsync(TestContext.Current.CancellationToken));
}
}
}
@@ -6,8 +6,8 @@ using Musify.Application.Tests.TestSupport;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.PlayLists;
namespace Musify.Application.Tests.PlayLists
{
public sealed class UpdatePlayListCommandHandlerTests : HandlerTestBase
{
private readonly IEventBus eventBus = Substitute.For<IEventBus>();
@@ -78,3 +78,4 @@ public sealed class UpdatePlayListCommandHandlerTests : HandlerTestBase
Assert.Equal("Original description", result.Value.Description);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Tests.TestSupport;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Services;
namespace Musify.Application.Tests.Services
{
public sealed class TrackStreamIssuerTests : HandlerTestBase
{
private readonly IStreamTicketService ticketService = Substitute.For<IStreamTicketService>();
@@ -48,3 +48,4 @@ public sealed class TrackStreamIssuerTests : HandlerTestBase
ticketService.Received(1).IssueTicket(1, "Tracks/ProcessedAudios/folder-42/");
}
}
}
@@ -6,8 +6,8 @@ using Musify.Domain.ValueObjects;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Services;
namespace Musify.Application.Tests.Services
{
public sealed class UploadIntentValidatorTests : HandlerTestBase
{
private readonly IStorageService storageService = Substitute.For<IStorageService>();
@@ -143,3 +143,4 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
Assert.False(result.IsError);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Application.Tests.TestSupport;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Services;
namespace Musify.Application.Tests.Services
{
public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
{
private readonly IYouTubeMusicService youTubeMusicService = Substitute.For<IYouTubeMusicService>();
@@ -101,3 +101,4 @@ public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
Assert.Single(await Database.ExternalAlbums.ToListAsync(TestContext.Current.CancellationToken));
}
}
}
@@ -1,8 +1,8 @@
using Musify.Application.Shared;
using Xunit;
namespace Musify.Application.Tests.Shared;
namespace Musify.Application.Tests.Shared
{
public sealed class StorageKeyTests
{
[Fact]
@@ -38,3 +38,4 @@ public sealed class StorageKeyTests
Assert.Equal(string.Empty, StorageKey.Combine());
}
}
}
@@ -4,8 +4,8 @@ using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
using Xunit;
namespace Musify.Application.Tests.Shared;
namespace Musify.Application.Tests.Shared
{
public sealed class TrackApplicationResponseTests
{
[Fact]
@@ -50,3 +50,4 @@ public sealed class TrackApplicationResponseTests
Assert.Null(response.Artist);
}
}
}
@@ -2,8 +2,8 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Musify.Application.Tests.TestSupport;
namespace Musify.Application.Tests.TestSupport
{
/// <summary>
/// Base class for handler tests: gives every test method its own empty, isolated
/// <see cref="TestDatabase"/> (xUnit creates a new instance of the test class per test method,
@@ -31,3 +31,4 @@ public abstract class HandlerTestBase : IAsyncLifetime
await Database.SaveChangesAsync(CancellationToken.None);
}
}
}
@@ -1,7 +1,7 @@
using Musify.Application.Configuration;
namespace Musify.Application.Tests.TestSupport;
namespace Musify.Application.Tests.TestSupport
{
/// <summary>
/// Configuration POCOs with every <c>required</c> member filled and the rest left at their
/// production defaults, so handler tests don't have to know which fields matter for them.
@@ -22,3 +22,4 @@ public static class TestConfigurations
public static StreamGatewayConfiguration StreamGateway(string publicBaseUrl = "https://stream.musify.test") =>
new() { PublicBaseUrl = publicBaseUrl };
}
}
@@ -3,8 +3,8 @@ using Microsoft.EntityFrameworkCore;
using Musify.Application.Contracts;
using Musify.Domain.Entities;
namespace Musify.Application.Tests.TestSupport;
namespace Musify.Application.Tests.TestSupport
{
/// <summary>
/// An <see cref="IDatabase"/> backed by a private, in-memory SQLite database.
/// </summary>
@@ -209,3 +209,4 @@ public sealed class TestDatabase : DbContext, IDatabase
public ValueTask DisposeAsync() => inner.DisposeAsync();
}
}
}
@@ -1,8 +1,8 @@
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
namespace Musify.Application.Tests.TestSupport;
namespace Musify.Application.Tests.TestSupport
{
/// <summary>
/// Builds fully-populated domain entities for tests, with sensible defaults for every
/// <c>required</c> member. Every factory always returns a valid instance — never null — so
@@ -235,3 +235,4 @@ public static class TestEntities
ListenedAt = listenedAt ?? DateTime.UtcNow
};
}
}
@@ -7,8 +7,8 @@ using Musify.Domain.ValueObjects;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class CreateTrackCommandHandlerTests : HandlerTestBase
{
private readonly IEventBus eventBus = Substitute.For<IEventBus>();
@@ -96,3 +96,4 @@ public sealed class CreateTrackCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
}
}
@@ -6,8 +6,8 @@ using Musify.Domain.ValueObjects;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class DeleteTrackCommandHandlerTests : HandlerTestBase
{
private readonly IEventBus eventBus = Substitute.For<IEventBus>();
@@ -74,3 +74,4 @@ public sealed class DeleteTrackCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Tracks;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class GetListeningHistoryQueryHandlerTests : HandlerTestBase
{
private GetListeningHistoryQueryHandler CreateHandler() => new(Database);
@@ -36,3 +36,4 @@ public sealed class GetListeningHistoryQueryHandlerTests : HandlerTestBase
Assert.Empty(result);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Tracks;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class GetTrackByIdQueryHandlerTests : HandlerTestBase
{
private GetTrackByIdQueryHandler CreateHandler() => new(Database);
@@ -32,3 +32,4 @@ public sealed class GetTrackByIdQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Tracks;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class GetTrackCoverQueryHandlerTests : HandlerTestBase
{
private GetTrackCoverQueryHandler CreateHandler() =>
@@ -49,3 +49,4 @@ public sealed class GetTrackCoverQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -7,8 +7,8 @@ using Musify.Application.Tracks;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class GetTrackStreamQueryHandlerTests : HandlerTestBase
{
private readonly IStreamTicketService ticketService = Substitute.For<IStreamTicketService>();
@@ -65,3 +65,4 @@ public sealed class GetTrackStreamQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Tracks;
using Musify.Domain.Entities;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class GetTracksByUserIdQueryHandlerTests : HandlerTestBase
{
private GetTracksByUserIdQueryHandler CreateHandler() => new(Database);
@@ -43,3 +43,4 @@ public sealed class GetTracksByUserIdQueryHandlerTests : HandlerTestBase
Assert.Equal(expectedPageNumber, result.Value.PageNumber);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Tracks;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class GetTracksQueryHandlerTests : HandlerTestBase
{
private GetTracksQueryHandler CreateHandler() => new(Database);
@@ -43,3 +43,4 @@ public sealed class GetTracksQueryHandlerTests : HandlerTestBase
Assert.Equal("Bohemian Rhapsody", track.Title);
}
}
}
@@ -9,8 +9,8 @@ using Musify.Domain.ValueObjects;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.Tracks;
namespace Musify.Application.Tests.Tracks
{
public sealed class RequestTrackUploadUrlsCommandHandlerTests : HandlerTestBase
{
private readonly IStorageService storageService = Substitute.For<IStorageService>();
@@ -78,3 +78,4 @@ public sealed class RequestTrackUploadUrlsCommandHandlerTests : HandlerTestBase
Assert.Equal(1, await Database.UploadIntents.CountAsync(TestContext.Current.CancellationToken));
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Users;
using Xunit;
namespace Musify.Application.Tests.Users;
namespace Musify.Application.Tests.Users
{
public sealed class CreateUserCommandHandlerTests : HandlerTestBase
{
private CreateUserCommandHandler CreateHandler() => new(Database, NoOpLogger<CreateUserCommandHandler>());
@@ -38,3 +38,4 @@ public sealed class CreateUserCommandHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
}
}
@@ -3,8 +3,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Users;
using Xunit;
namespace Musify.Application.Tests.Users;
namespace Musify.Application.Tests.Users
{
public sealed class GetUserByIdQueryHandlerTests : HandlerTestBase
{
private GetUserByIdQueryHandler CreateHandler() => new(Database);
@@ -29,3 +29,4 @@ public sealed class GetUserByIdQueryHandlerTests : HandlerTestBase
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Users;
using Xunit;
namespace Musify.Application.Tests.Users;
namespace Musify.Application.Tests.Users
{
public sealed class GetUsersQueryHandlerTests : HandlerTestBase
{
private GetUsersQueryHandler CreateHandler() => new(Database);
@@ -31,3 +31,4 @@ public sealed class GetUsersQueryHandlerTests : HandlerTestBase
Assert.Equal(1, user.Id);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Application.Tests.TestSupport;
using Musify.Application.Users;
using Xunit;
namespace Musify.Application.Tests.Users;
namespace Musify.Application.Tests.Users
{
public sealed class SyncUserCommandHandlerTests : HandlerTestBase
{
private SyncUserCommandHandler CreateHandler() => new(Database, NoOpLogger<SyncUserCommandHandler>());
@@ -40,3 +40,4 @@ public sealed class SyncUserCommandHandlerTests : HandlerTestBase
Assert.Equal("https://avatar.example/new.png", stored.ProfilePictureUrl);
}
}
}
@@ -7,8 +7,8 @@ using Musify.Application.YouTube;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.YouTube;
namespace Musify.Application.Tests.YouTube
{
public sealed class GetYouTubeAlbumQueryHandlerTests : HandlerTestBase
{
private readonly IYouTubeMusicService youTubeMusicService = Substitute.For<IYouTubeMusicService>();
@@ -59,3 +59,4 @@ public sealed class GetYouTubeAlbumQueryHandlerTests : HandlerTestBase
Assert.True(result.IsError);
}
}
}
@@ -7,8 +7,8 @@ using Musify.Application.YouTube.Responses;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.YouTube;
namespace Musify.Application.Tests.YouTube
{
public sealed class ResolveYouTubeTrackStreamCommandHandlerTests : HandlerTestBase
{
private readonly IYouTubeMusicService youTubeMusicService = Substitute.For<IYouTubeMusicService>();
@@ -63,3 +63,4 @@ public sealed class ResolveYouTubeTrackStreamCommandHandlerTests : HandlerTestBa
Assert.Equal(42, history.UserId);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.YouTube;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.YouTube;
namespace Musify.Application.Tests.YouTube
{
public sealed class SearchYouTubeAlbumsQueryHandlerTests
{
private readonly IYouTubeMusicService youTubeMusicService = Substitute.For<IYouTubeMusicService>();
@@ -34,3 +34,4 @@ public sealed class SearchYouTubeAlbumsQueryHandlerTests
Assert.Same(expected, result.Value);
}
}
}
@@ -4,8 +4,8 @@ using Musify.Application.YouTube;
using NSubstitute;
using Xunit;
namespace Musify.Application.Tests.YouTube;
namespace Musify.Application.Tests.YouTube
{
public sealed class SearchYouTubeTracksQueryHandlerTests
{
private readonly IYouTubeMusicService youTubeMusicService = Substitute.For<IYouTubeMusicService>();
@@ -34,3 +34,4 @@ public sealed class SearchYouTubeTracksQueryHandlerTests
Assert.Same(expected, result.Value);
}
}
}
@@ -1,8 +1,8 @@
using Musify.Domain.ValueObjects;
using Xunit;
namespace Musify.Domain.Tests.ValueObjects;
namespace Musify.Domain.Tests.ValueObjects
{
public sealed class TrackAudioTests
{
[Theory]
@@ -20,3 +20,4 @@ public sealed class TrackAudioTests
Assert.Equal(expectedInProgress, audio.IsInProgress);
}
}
}
@@ -1,8 +1,8 @@
using Musify.Domain.ValueObjects;
using Xunit;
namespace Musify.Domain.Tests.ValueObjects;
namespace Musify.Domain.Tests.ValueObjects
{
public sealed class TrackPicturesTests
{
[Theory]
@@ -17,3 +17,4 @@ public sealed class TrackPicturesTests
Assert.Equal(expected, pictures.IsProcessed);
}
}
}
@@ -2,8 +2,8 @@ using Musify.Domain.Entities;
using Musify.Infrastructure.Tests.TestSupport;
using Xunit;
namespace Musify.Infrastructure.Tests.Persistence;
namespace Musify.Infrastructure.Tests.Persistence
{
[Collection(InfrastructureCollection.Name)]
public sealed class AuditableEntityInterceptorTests(InfrastructureTestFixture fixture)
{
@@ -43,3 +43,4 @@ public sealed class AuditableEntityInterceptorTests(InfrastructureTestFixture fi
$"original-created-at={originalCreatedAt:O}, final-updated-at={user.UpdatedAt:O}");
}
}
}
@@ -4,8 +4,8 @@ using Musify.Domain.ValueObjects;
using Musify.Infrastructure.Tests.TestSupport;
using Xunit;
namespace Musify.Infrastructure.Tests.Persistence;
namespace Musify.Infrastructure.Tests.Persistence
{
[Collection(InfrastructureCollection.Name)]
public sealed class DatabaseTests(InfrastructureTestFixture fixture)
{
@@ -89,3 +89,4 @@ public sealed class DatabaseTests(InfrastructureTestFixture fixture)
Audio = new TrackAudio()
};
}
}
@@ -2,8 +2,8 @@ using ErrorOr;
using Musify.Infrastructure.Services;
using Xunit;
namespace Musify.Infrastructure.Tests.Services;
namespace Musify.Infrastructure.Tests.Services
{
public sealed class DisabledYouTubeMusicServiceTests
{
private readonly DisabledYouTubeMusicService service = new();
@@ -56,3 +56,4 @@ public sealed class DisabledYouTubeMusicServiceTests
Assert.Equal("https://img.example/thumb.jpg", result);
}
}
}
@@ -4,8 +4,8 @@ using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
namespace Musify.Infrastructure.Tests.Services;
namespace Musify.Infrastructure.Tests.Services
{
public sealed class PictureServiceTests
{
private static PictureService CreateService() => new(NullLogger<PictureService>.Instance);
@@ -55,3 +55,4 @@ public sealed class PictureServiceTests
Assert.Equal(50, result.Height);
}
}
}
@@ -7,8 +7,8 @@ using Musify.Infrastructure.Services;
using Musify.Infrastructure.Tests.TestSupport;
using Xunit;
namespace Musify.Infrastructure.Tests.Services;
namespace Musify.Infrastructure.Tests.Services
{
[Collection(InfrastructureCollection.Name)]
public sealed class PlayListPresetSeederTests(InfrastructureTestFixture fixture)
{
@@ -100,3 +100,4 @@ public sealed class PlayListPresetSeederTests(InfrastructureTestFixture fixture)
Assert.Null(metadata);
}
}
}
@@ -3,8 +3,8 @@ using Microsoft.Extensions.Caching.Memory;
using Musify.Infrastructure.Services;
using Xunit;
namespace Musify.Infrastructure.Tests.Services;
namespace Musify.Infrastructure.Tests.Services
{
public sealed class SingleFlightCacheTests
{
private static SingleFlightCache CreateCache() => new(new MemoryCache(new MemoryCacheOptions()));
@@ -78,3 +78,4 @@ public sealed class SingleFlightCacheTests
Assert.Equal(2, calls);
}
}
}
@@ -8,8 +8,8 @@ using Musify.Infrastructure.Services;
using Musify.Infrastructure.Tests.TestSupport;
using Xunit;
namespace Musify.Infrastructure.Tests.Services;
namespace Musify.Infrastructure.Tests.Services
{
[Collection(InfrastructureCollection.Name)]
public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAsyncLifetime
{
@@ -149,3 +149,4 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
Assert.Equal("presigned content".Length, metadata.ContentLength);
}
}
}
@@ -5,8 +5,8 @@ using Musify.Infrastructure.Configuration;
using Musify.Infrastructure.Services;
using Xunit;
namespace Musify.Infrastructure.Tests.Services;
namespace Musify.Infrastructure.Tests.Services
{
public sealed class StreamTicketServiceTests : IDisposable
{
private readonly string privateKeyPath = Path.GetTempFileName();
@@ -69,3 +69,4 @@ public sealed class StreamTicketServiceTests : IDisposable
Assert.True(result.IsValid);
}
}
}
@@ -10,8 +10,8 @@ using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;
using Xunit;
namespace Musify.Infrastructure.Tests.TestSupport;
namespace Musify.Infrastructure.Tests.TestSupport
{
/// <summary>
/// One Postgres container and one SeaweedFS container (same image and startup
/// command as <c>deploy/compose.yml</c>), started once for every test in the
@@ -115,3 +115,4 @@ public sealed class InfrastructureCollection : ICollectionFixture<Infrastructure
{
public const string Name = "Infrastructure";
}
}
@@ -6,8 +6,8 @@ using Musify.StreamingGateway.Authentication;
using Musify.StreamingGateway.Configuration;
using Xunit;
namespace Musify.StreamingGateway.Tests.Authentication;
namespace Musify.StreamingGateway.Tests.Authentication
{
public sealed class TicketValidatorTests : IDisposable
{
private const string Issuer = "musify-webapi";
@@ -144,3 +144,4 @@ public sealed class TicketValidatorTests : IDisposable
Assert.Equal(string.Empty, prefix);
}
}
}
@@ -9,8 +9,8 @@ using Musify.StreamingGateway.Configuration;
using Musify.StreamingGateway.Middleware;
using Xunit;
namespace Musify.StreamingGateway.Tests.Middleware;
namespace Musify.StreamingGateway.Tests.Middleware
{
public sealed class TicketValidationMiddlewareTests : IDisposable
{
private const string Prefix = "Tracks/ProcessedAudios/abc";
@@ -151,3 +151,4 @@ public sealed class TicketValidationMiddlewareTests : IDisposable
Assert.True(wasNextCalled());
}
}
}