using System; using System.Threading.Tasks; using ImageCatalog_2; using ImageCatalog_2.Services; using MaddoShared; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using NSubstitute; using Shouldly; namespace MaddoShared.Tests; [TestClass] public class DataModelCharacterizationTests { [TestMethod] public void SelectSourceFolderCommand_RaisesEvent() { var model = CreateModel(); var raised = false; model.SelectSourceFolderRequested += (_, _) => raised = true; model.SelectSourceFolderCommand.Execute(null); raised.ShouldBeTrue(); } [TestMethod] public async Task SaveSettingsToFileAsync_DelegatesToSettingsService() { var settingsService = Substitute.For(); settingsService .SaveSettingsAsync(Arg.Any(), Arg.Any()) .Returns(Task.CompletedTask); var model = CreateModel(settingsService: settingsService); await model.SaveSettingsToFileAsync("settings.xml"); await settingsService.Received(1) .SaveSettingsAsync("settings.xml", model); } [TestMethod] public async Task LoadSettingsFromFileAsync_DelegatesToSettingsService() { var settingsService = Substitute.For(); settingsService .LoadSettingsAsync(Arg.Any(), Arg.Any()) .Returns(Task.CompletedTask); var model = CreateModel(settingsService: settingsService); await model.LoadSettingsFromFileAsync("settings.xml"); await settingsService.Received(1) .LoadSettingsAsync("settings.xml", model); } [TestMethod] public void ThumbnailOptionIndex_UpdatesAuthoritativeThumbnailState() { var model = CreateModel(); model.ThumbnailOptionIndex = (int)DataModel.ThumbnailOptionEnum.RaceTime; model.ThumbnailOption.ShouldBe(DataModel.ThumbnailOptionEnum.RaceTime); model.AddRaceTimeToThumbnails.ShouldBeTrue(); model.ThumbnailMode.ShouldBe("RaceTime"); } [TestMethod] public void ProcessingChildChange_RaisesDataModelPropertyChanged() { var model = CreateModel(); string? changed = null; model.PropertyChanged += (_, args) => changed = args.PropertyName; model.Processing.SpeedCounter = "12.00 f/s"; changed.ShouldBe(nameof(DataModel.SpeedCounter)); model.SpeedCounter.ShouldBe("12.00 f/s"); } [TestMethod] public void PathsNormalize_UpdatesFlattenedSourceAndDestination() { var model = CreateModel(); model.SourcePath = "\"C:/input\""; model.DestinationPath = "C:/output"; model.Paths.NormalizePaths(); model.SourcePath.ShouldBe($"C:{System.IO.Path.DirectorySeparatorChar}input{System.IO.Path.DirectorySeparatorChar}"); model.DestinationPath.ShouldBe($"C:{System.IO.Path.DirectorySeparatorChar}output{System.IO.Path.DirectorySeparatorChar}"); } [TestMethod] public void AiChildChange_RaisesDataModelPropertyChanged() { var model = CreateModel(); string? changed = null; model.PropertyChanged += (_, args) => changed = args.PropertyName; model.Ai.ModelsFolderPath = "K:/models"; changed.ShouldBe(nameof(DataModel.ModelsFolderPath)); model.ModelsFolderPath.ShouldBe("K:/models"); } [TestMethod] public void RaceUploadChildChange_RaisesDataModelPropertyChanged() { var model = CreateModel(); string? changed = null; model.PropertyChanged += (_, args) => changed = args.PropertyName; model.RaceUpload.ApiLogin = "admin"; changed.ShouldBe(nameof(DataModel.ApiLogin)); model.ApiLogin.ShouldBe("admin"); } [TestMethod] public void VisualChildChange_RaisesDataModelPropertyChanged() { var model = CreateModel(); string? changed = null; model.PropertyChanged += (_, args) => changed = args.PropertyName; model.Visual.FontSize = 42; changed.ShouldBe(nameof(DataModel.FontSize)); model.FontSize.ShouldBe(42); } private static DataModel CreateModel( ISettingsService? settingsService = null, ITestService? testService = null) { var mapper = Substitute.For(); var picSettings = new PicSettings(); var imageCreator = Substitute.For(); imageCreator .CreateImageAsync(Arg.Any(), Arg.Any()) .Returns(Task.CompletedTask); var imageCreationService = new ImageCreationService( Substitute.For>(), picSettings, imageCreator); var imageProcessingCoordinator = new ImageProcessingCoordinator( imageCreationService, Substitute.For>()); var aiExtractionService = new AiExtractionService( Substitute.For>()); return new DataModel( testService ?? Substitute.For(), settingsService ?? Substitute.For(), imageCreationService, aiExtractionService, imageProcessingCoordinator, picSettings, mapper, Substitute.For>(), versionProvider: null); } }