Files
PLib/tests/PLib.Tests/Settings/SettingsViewModelTests.cs
T

126 lines
4.6 KiB
C#

using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using PLib.Application.Library;
using PLib.Application.Metadata;
using PLib.Desktop.Services;
using PLib.Desktop.Settings;
using PLib.Desktop.ViewModels;
using Shouldly;
namespace PLib.Tests.Settings;
public sealed class SettingsViewModelTests
{
private readonly IAppSettingsStore _store = Substitute.For<IAppSettingsStore>();
[Fact]
public async Task Opening_and_saving_without_touching_anything_changes_nothing()
{
// Both of these are displayed in a lossier unit than they are stored in: 65 536 bytes
// shows as 0,06 MB. Converting the untouched field back used to yield 62 915, which
// silently rewrote the setting and forced a full rescan on every visit to the panel.
var options = new LibraryOptions
{
Folders = [@"C:\videos"],
MinimumFileSizeInBytes = 65_536,
ThumbnailPositionRatio = 0.15,
};
var (viewModel, outcome) = await SaveAsync(options);
outcome.RescanRequired.ShouldBeFalse();
Written.MinimumFileSizeInBytes.ShouldBe(65_536);
Written.ThumbnailPositionRatio.ShouldBe(0.15);
viewModel.HasFolders.ShouldBeTrue();
}
[Fact]
public async Task Editing_the_minimum_size_does_write_the_new_value()
{
var (_, outcome) = await SaveAsync(
new LibraryOptions { Folders = [@"C:\videos"], MinimumFileSizeInBytes = 65_536 },
viewModel => viewModel.MinimumFileSizeMegabytes = 4);
Written.MinimumFileSizeInBytes.ShouldBe(4 * 1024 * 1024);
outcome.RescanRequired.ShouldBeTrue();
}
[Fact]
public async Task Removing_a_folder_is_carried_into_the_saved_settings()
{
var (_, outcome) = await SaveAsync(
new LibraryOptions { Folders = [@"C:\a", @"C:\b"] },
viewModel => viewModel.Folders[0].RemoveCommand.Execute().Subscribe());
Written.Folders.ShouldBe([@"C:\b"]);
outcome.RescanRequired.ShouldBeTrue();
}
[Fact]
public async Task Saving_the_panel_keeps_the_settings_it_does_not_edit()
{
// The panel writes the whole file, so anything outside its own screens — the
// playback volume, for one — has to be carried through untouched.
await SaveAsync(
new LibraryOptions { Folders = [@"C: ideos"] },
viewModel => viewModel.ThumbnailWidth = 720,
new PlaybackOptions { Volume = 0.42, IsMuted = true });
Written.ThumbnailWidth.ShouldBe(720);
Written.Volume.ShouldBe(0.42);
Written.IsMuted.ShouldBeTrue();
}
[Fact]
public async Task Cancelling_writes_nothing()
{
var viewModel = Create(new LibraryOptions { Folders = [@"C:\videos"] });
var closed = viewModel.Closed.FirstAsync().ToTask();
viewModel.MinimumFileSizeMegabytes = 999;
await viewModel.CancelCommand.Execute().FirstAsync().ToTask(TestContext.Current.CancellationToken);
(await closed).Saved.ShouldBeFalse();
_store.ReceivedCalls().ShouldNotContain(call => call.GetMethodInfo().Name == nameof(IAppSettingsStore.SaveAsync));
}
private AppSettings Written =>
(AppSettings)_store.ReceivedCalls()
.Single(call => call.GetMethodInfo().Name == nameof(IAppSettingsStore.SaveAsync))
.GetArguments()[0]!;
private async Task<(SettingsViewModel ViewModel, SettingsDialogOutcome Outcome)> SaveAsync(
LibraryOptions options,
Action<SettingsViewModel>? edit = null,
PlaybackOptions? playback = null)
{
var viewModel = Create(options, playback);
var closed = viewModel.Closed.FirstAsync().ToTask();
edit?.Invoke(viewModel);
await viewModel.SaveCommand.Execute().FirstAsync().ToTask(TestContext.Current.CancellationToken);
return (viewModel, await closed);
}
private SettingsViewModel Create(LibraryOptions options, PlaybackOptions? playback = null)
{
_store.Current.Returns(
AppSettings.From(
options,
new AppearanceOptions(),
playback ?? new PlaybackOptions(),
new MetadataOptions()));
return new SettingsViewModel(
Substitute.For<IServiceScopeFactory>(),
_store,
Substitute.For<IFolderPicker>(),
Substitute.For<IThemeService>(),
NullLogger<SettingsViewModel>.Instance);
}
}