diff --git a/Build.fsx b/Build.fsx index 069c357e..3b81ceed 100644 --- a/Build.fsx +++ b/Build.fsx @@ -120,6 +120,10 @@ Target.create "TestData" (fun _ -> test "SonOfPicasso.Data.Tests" "netcoreapp3.0" "datatest" ) +Target.create "TestIntegration" (fun _ -> + test "SonOfPicasso.Core.IntegrationTests" "netcoreapp3.0" "integration" +) + Target.create "Package" (fun _ -> let packagePath = (sprintf "build/son-of-picasso-%s.zip" fullSemver) @@ -142,6 +146,7 @@ open Fake.Core.TargetOperators "Build" ==> "TestCore" ==> "Test" "Build" ==> "TestUI" ==> "Test" "Build" ==> "TestData" ==> "Test" +"Build" ==> "TestIntegration" ==> "Test" "Build" ==> "Test" ==> "Default" "Build" ==> "Package" ==> "Default" diff --git a/SonOfPicasso.sln b/SonOfPicasso.sln index 6d8fe49c..7e48d22c 100644 --- a/SonOfPicasso.sln +++ b/SonOfPicasso.sln @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SonOfPicasso.UI", "src\SonO EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SonOfPicasso.UI.Tests", "src\SonOfPicasso.UI.Tests\SonOfPicasso.UI.Tests.csproj", "{9D06ACFE-6ECD-4EC9-9CA9-8D6CCC5C362A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SonOfPicasso.Core.IntegrationTests", "src\SonOfPicasso.Core.IntegrationTests\SonOfPicasso.Core.IntegrationTests.csproj", "{B86E824C-FAAA-4DBC-B6A9-292D0CEC5797}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -71,6 +73,10 @@ Global {9D06ACFE-6ECD-4EC9-9CA9-8D6CCC5C362A}.Debug|Any CPU.Build.0 = Debug|Any CPU {9D06ACFE-6ECD-4EC9-9CA9-8D6CCC5C362A}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D06ACFE-6ECD-4EC9-9CA9-8D6CCC5C362A}.Release|Any CPU.Build.0 = Release|Any CPU + {B86E824C-FAAA-4DBC-B6A9-292D0CEC5797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B86E824C-FAAA-4DBC-B6A9-292D0CEC5797}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B86E824C-FAAA-4DBC-B6A9-292D0CEC5797}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B86E824C-FAAA-4DBC-B6A9-292D0CEC5797}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,6 +87,7 @@ Global {1D87A79F-C5D4-4EA0-B978-13E942B9CEE9} = {12E2CEF6-EB9D-412F-98E3-ECBBBD00A29A} {2F6B9B2C-D228-4563-B74C-12C18E753361} = {12E2CEF6-EB9D-412F-98E3-ECBBBD00A29A} {9D06ACFE-6ECD-4EC9-9CA9-8D6CCC5C362A} = {12E2CEF6-EB9D-412F-98E3-ECBBBD00A29A} + {B86E824C-FAAA-4DBC-B6A9-292D0CEC5797} = {12E2CEF6-EB9D-412F-98E3-ECBBBD00A29A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2C01583D-05D7-4F03-A86C-ECF79DA041D0} diff --git a/src/SonOfPicasso.Core.IntegrationTests/Services/ImageManagementServiceTests.cs b/src/SonOfPicasso.Core.IntegrationTests/Services/ImageManagementServiceTests.cs new file mode 100644 index 00000000..535ae711 --- /dev/null +++ b/src/SonOfPicasso.Core.IntegrationTests/Services/ImageManagementServiceTests.cs @@ -0,0 +1,34 @@ +using System; +using Autofac.Extras.NSubstitute; +using SonOfPicasso.Data.Repository; +using SonOfPicasso.Data.Tests; +using SonOfPicasso.Testing.Common; +using Xunit; +using Xunit.Abstractions; + +namespace SonOfPicasso.Core.IntegrationTests.Services +{ + public class ImageManagementServiceTests : DataTestsBase, IDisposable + { + private readonly AutoSubstitute _autoSubstitute; + + public ImageManagementServiceTests(ITestOutputHelper testOutputHelper) + : base(testOutputHelper) + { + _autoSubstitute = new AutoSubstitute(); + _autoSubstitute.Provide>(CreateUnitOfWork); + } + + [Fact] + public void CanInitialize() + { + var imageManagementService = _autoSubstitute.Resolve(); + } + + public new void Dispose() + { + _autoSubstitute.Dispose(); + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/SonOfPicasso.Core.IntegrationTests/SonOfPicasso.Core.IntegrationTests.csproj b/src/SonOfPicasso.Core.IntegrationTests/SonOfPicasso.Core.IntegrationTests.csproj new file mode 100644 index 00000000..cf37b91a --- /dev/null +++ b/src/SonOfPicasso.Core.IntegrationTests/SonOfPicasso.Core.IntegrationTests.csproj @@ -0,0 +1,30 @@ + + + + netcoreapp3.0 + + false + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/SonOfPicasso.Core.Tests/Services/DataCacheTests.cs b/src/SonOfPicasso.Core.Tests/Services/DataCacheTests.cs index 8e76e2c7..0189770b 100644 --- a/src/SonOfPicasso.Core.Tests/Services/DataCacheTests.cs +++ b/src/SonOfPicasso.Core.Tests/Services/DataCacheTests.cs @@ -16,311 +16,109 @@ namespace SonOfPicasso.Core.Tests.Services { - public class DataCacheTests : TestsBase + public class DataCacheTests : TestsBase, IDisposable { + private readonly AutoSubstitute _autoSub; + public DataCacheTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { + _autoSub = new AutoSubstitute(); } - [Fact] - public void CanSetUserSettings() - { - Logger.Debug("CanSetUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); - - var dataCache = autoSub.Resolve(); - - dataCache.SetUserSettings(new UserSettings()) - .Subscribe(_ => autoResetEvent.Set()); - - autoResetEvent.WaitOne(); - - string[] keys = null; - - inMemoryBlobCache.GetAllKeys() - .Subscribe(enumerable => - { - keys = enumerable.ToArray(); - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - keys.Should().NotBeNull(); - keys.Should().Contain("UserSettings"); - } - } - - [Fact] - public void CanRetrieveUserSettings() - { - Logger.Debug("CanRetrieveUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); - - var dataCache = autoSub.Resolve(); - - var input = new UserSettings(); - dataCache.SetUserSettings(input) - .Subscribe(_ => autoResetEvent.Set()); - - autoResetEvent.WaitOne(); - - UserSettings output = null; - - dataCache.GetUserSettings() - .Subscribe(settings => - { - output = settings; - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - output.Should().NotBeNull(); - // output.Should().BeEquivalentTo(input); - } - } - - [Fact] - public void CanCreateUserSettings() + public void Dispose() { - Logger.Debug("CanCreateUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); - - var dataCache = autoSub.Resolve(); - - UserSettings userSettings = null; - - dataCache.GetUserSettings() - .Subscribe(settings => - { - userSettings = settings; - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - userSettings.Should().NotBeNull(); - } + _autoSub.Dispose(); } [Fact] - public void CanSetFolderList() + public void CanSetUserSettings() { Logger.Debug("CanSetUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); + var autoResetEvent = new AutoResetEvent(false); - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); + var inMemoryBlobCache = new InMemoryBlobCache(); + _autoSub.Provide(inMemoryBlobCache); - var dataCache = autoSub.Resolve(); + var dataCache = _autoSub.Resolve(); - dataCache.SetFolderList(new string[0]) + dataCache.SetUserSettings(new UserSettings()) .Subscribe(_ => autoResetEvent.Set()); - autoResetEvent.WaitOne(); + autoResetEvent.WaitOne(); - string[] keys = null; + string[] keys = null; - inMemoryBlobCache.GetAllKeys() - .Subscribe(enumerable => - { - keys = enumerable.ToArray(); - autoResetEvent.Set(); - }); + inMemoryBlobCache.GetAllKeys() + .Subscribe(enumerable => + { + keys = enumerable.ToArray(); + autoResetEvent.Set(); + }); - autoResetEvent.WaitOne(); + autoResetEvent.WaitOne(); - keys.Should().NotBeNull(); - keys.Should().Contain("ImageFolders"); - } + keys.Should().NotBeNull(); + keys.Should().Contain("UserSettings"); } [Fact] - public void CanRetrieveFolderList() - { - Logger.Debug("CanRetrieveUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); - - var dataCache = autoSub.Resolve(); - - var input = Faker.Lorem.Words(); - - dataCache.SetFolderList(input) - .Subscribe(_ => autoResetEvent.Set()); - - autoResetEvent.WaitOne(); - - string[] output = null; - - dataCache.GetFolderList() - .Subscribe(folders => - { - output = folders; - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - output.Should().NotBeNull(); - output.Should().BeEquivalentTo(input); - } - } - - [Fact] - public void CanCreateFolderList() - { - Logger.Debug("CanCreateUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); - - var dataCache = autoSub.Resolve(); - - string[] output = null; - - dataCache.GetFolderList() - .Subscribe(folders => - { - output = folders; - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - output.Should().NotBeNull(); - output.Should().BeEmpty(); - } - } - - [Fact] - public void CanSetImageFolder() - { - Logger.Debug("CanSetUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); - - var dataCache = autoSub.Resolve(); - - var imageFolder = DataGenerator.ImageFolderFaker.Generate(); - - dataCache.SetFolder(imageFolder) - .Subscribe(_ => autoResetEvent.Set()); - - autoResetEvent.WaitOne(); - - string[] keys = null; - - inMemoryBlobCache.GetAllKeys() - .Subscribe(enumerable => - { - keys = enumerable.ToArray(); - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - keys.Should().NotBeNull(); - keys.Should().Contain($"ImageFolder {imageFolder.Path}"); - } - } - - [Fact] - public void CanRetrieveImageFolder() + public void CanRetrieveUserSettings() { Logger.Debug("CanRetrieveUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); + var autoResetEvent = new AutoResetEvent(false); - var dataCache = autoSub.Resolve(); + var inMemoryBlobCache = new InMemoryBlobCache(); + _autoSub.Provide(inMemoryBlobCache); - var input = DataGenerator.ImageFolderFaker.Generate(); + var dataCache = _autoSub.Resolve(); - dataCache.SetFolder(input) - .Subscribe(_ => autoResetEvent.Set()); + var input = new UserSettings(); + dataCache.SetUserSettings(input) + .Subscribe(_ => autoResetEvent.Set()); - autoResetEvent.WaitOne(); + autoResetEvent.WaitOne(); - ImageFolderModel output = null; + UserSettings output = null; - dataCache.GetFolder(input.Path) - .Subscribe(folder => - { - output = folder; - autoResetEvent.Set(); - }); + dataCache.GetUserSettings() + .Subscribe(settings => + { + output = settings; + autoResetEvent.Set(); + }); - autoResetEvent.WaitOne(); + autoResetEvent.WaitOne(); - output.Should().NotBeNull(); - output.Should().BeEquivalentTo(input); - } + output.Should().NotBeNull(); + + // TODO: Remove comment after there are fields in UserSettings + // output.Should().BeEquivalentTo(input); } [Fact] - public void CanCreateImageFolder() + public void CanCreateUserSettings() { Logger.Debug("CanCreateUserSettings"); - using (var autoSub = new AutoSubstitute()) - { - var autoResetEvent = new AutoResetEvent(false); - - var inMemoryBlobCache = new InMemoryBlobCache(); - autoSub.Provide(inMemoryBlobCache); + var autoResetEvent = new AutoResetEvent(false); - var dataCache = autoSub.Resolve(); + var inMemoryBlobCache = new InMemoryBlobCache(); + _autoSub.Provide(inMemoryBlobCache); - ImageFolderModel output = null; + var dataCache = _autoSub.Resolve(); - var path = Faker.System.DirectoryPathWindows(); + UserSettings userSettings = null; - dataCache.GetFolder(path) - .Subscribe(folder => - { - output = folder; - autoResetEvent.Set(); - }); + dataCache.GetUserSettings() + .Subscribe(settings => + { + userSettings = settings; + autoResetEvent.Set(); + }); - autoResetEvent.WaitOne(); + autoResetEvent.WaitOne(); - output.Should().NotBeNull(); - output.Path.Should().Be(path); - output.Images.Should().BeEmpty(); - } + userSettings.Should().NotBeNull(); } } } \ No newline at end of file diff --git a/src/SonOfPicasso.Core.Tests/Services/ImageLocationServiceTests.cs b/src/SonOfPicasso.Core.Tests/Services/ImageLocationServiceTests.cs index af303a46..487249ed 100644 --- a/src/SonOfPicasso.Core.Tests/Services/ImageLocationServiceTests.cs +++ b/src/SonOfPicasso.Core.Tests/Services/ImageLocationServiceTests.cs @@ -4,7 +4,6 @@ using System.IO.Abstractions.TestingHelpers; using System.Linq; using System.Threading; -using Autofac; using Autofac.Extras.NSubstitute; using FluentAssertions; using SonOfPicasso.Core.Scheduling; @@ -19,59 +18,59 @@ namespace SonOfPicasso.Core.Tests.Services { public class ImageLocationServiceTests : TestsBase { + private readonly AutoSubstitute _autoSub; + public ImageLocationServiceTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { + _autoSub = new AutoSubstitute(); } [Fact(Timeout = 1000)] public void CanGetImages() { Logger.Debug("CanGetImages"); - using (var autoSub = new AutoSubstitute()) - { - var directory = Faker.System.DirectoryPathWindows(); + var directory = Faker.System.DirectoryPathWindows(); - var subDirectory = Path.Combine(directory, Faker.Random.Word()); + var subDirectory = Path.Combine(directory, Faker.Random.Word()); - var mockFileSystem = new MockFileSystem(); - autoSub.Provide(mockFileSystem); + var mockFileSystem = new MockFileSystem(); + _autoSub.Provide(mockFileSystem); - var files = new[] { "jpg", "jpeg", "png", "tiff", "tif", "bmp" } - .Select(ext => Path.Combine(subDirectory, Faker.System.FileName(ext))) - .ToArray(); + var files = new[] {"jpg", "jpeg", "png", "tiff", "tif", "bmp"} + .Select(ext => Path.Combine(subDirectory, Faker.System.FileName(ext))) + .ToArray(); - var otherFiles = new[] { "txt", "doc" } - .Select(ext => Path.Combine(subDirectory, Faker.System.FileName(ext))) - .ToArray(); + var otherFiles = new[] {"txt", "doc"} + .Select(ext => Path.Combine(subDirectory, Faker.System.FileName(ext))) + .ToArray(); - foreach (var file in files.Concat(otherFiles)) - { - mockFileSystem.AddFile(file, new MockFileData(new byte[0])); - } + foreach (var file in files.Concat(otherFiles)) + { + mockFileSystem.AddFile(file, new MockFileData(new byte[0])); + } - var autoResetEvent = new AutoResetEvent(false); + var autoResetEvent = new AutoResetEvent(false); - string[] imagePaths = null; + string[] imagePaths = null; - var testSchedulerProvider = new TestSchedulerProvider(); - autoSub.Provide(testSchedulerProvider); + var testSchedulerProvider = new TestSchedulerProvider(); + _autoSub.Provide(testSchedulerProvider); - var imageLocationService = autoSub.Resolve(); - imageLocationService.GetImages(directory) - .Subscribe(paths => - { - imagePaths = paths; - autoResetEvent.Set(); - }); + var imageLocationService = _autoSub.Resolve(); + imageLocationService.GetImages(directory) + .Subscribe(paths => + { + imagePaths = paths; + autoResetEvent.Set(); + }); - testSchedulerProvider.TaskPool.AdvanceBy(1); - autoResetEvent.WaitOne(); + testSchedulerProvider.TaskPool.AdvanceBy(1); + autoResetEvent.WaitOne(); - imagePaths.Should().NotBeNull(); - imagePaths.Select(fileInfo => fileInfo) - .Should().BeEquivalentTo(files); - } + imagePaths.Should().NotBeNull(); + imagePaths.Select(fileInfo => fileInfo) + .Should().BeEquivalentTo(files); } } } \ No newline at end of file diff --git a/src/SonOfPicasso.Core.Tests/Services/ImageManagementServiceTests.cs b/src/SonOfPicasso.Core.Tests/Services/ImageManagementServiceTests.cs index 87c2c17e..808a4f7d 100644 --- a/src/SonOfPicasso.Core.Tests/Services/ImageManagementServiceTests.cs +++ b/src/SonOfPicasso.Core.Tests/Services/ImageManagementServiceTests.cs @@ -1,367 +1,157 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; using System.Linq; -using System.Reactive; +using System.Linq.Expressions; using System.Reactive.Linq; using System.Threading; using Autofac.Extras.NSubstitute; -using Bogus.Extensions; using FluentAssertions; using NSubstitute; using SonOfPicasso.Core.Interfaces; -using SonOfPicasso.Core.Models; +using SonOfPicasso.Core.Scheduling; using SonOfPicasso.Core.Services; +using SonOfPicasso.Data.Model; +using SonOfPicasso.Data.Repository; using SonOfPicasso.Testing.Common; using SonOfPicasso.Testing.Common.Extensions; -using SonOfPicasso.Testing.Common.Services; +using SonOfPicasso.Testing.Common.Scheduling; using Xunit; using Xunit.Abstractions; +using Directory = SonOfPicasso.Data.Model.Directory; namespace SonOfPicasso.Core.Tests.Services { - public class ImageManagementServiceTests : TestsBase + public class ImageManagementServiceTests : TestsBase, IDisposable { public ImageManagementServiceTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { - } + _autoSubstitute = new AutoSubstitute(); - [Fact] - public void CantAddNullFolder() - { - Logger.Debug("CantAddNullFolder"); - using (var autoSub = new AutoSubstitute()) - { - var imageManagementService = autoSub.Resolve(); + _testSchedulerProvider = new TestSchedulerProvider(); + _autoSubstitute.Provide(_testSchedulerProvider); - var folder = Faker.System.DirectoryPathWindows(); + _unitOfWorkQueue = new Queue(); + _autoSubstitute.Provide>(() => _unitOfWorkQueue.Dequeue()); - Assert.Throws(() => imageManagementService.AddFolder(null)); - } + _mockFileSystem = new MockFileSystem(); + _autoSubstitute.Provide(_mockFileSystem); } - [Fact] - public void CantRemoveNullFolder() + public void Dispose() { - Logger.Debug("CantRemoveNullFolder"); - using (var autoSub = new AutoSubstitute()) - { - var imageManagementService = autoSub.Resolve(); - - var folder = Faker.System.DirectoryPathWindows(); - - Assert.Throws(() => imageManagementService.AddFolder(null)); - } + _autoSubstitute.Dispose(); } + private readonly AutoSubstitute _autoSubstitute; + private readonly Queue _unitOfWorkQueue; + private readonly MockFileSystem _mockFileSystem; + private readonly TestSchedulerProvider _testSchedulerProvider; + [Fact] - public void CantRemoveFolderThatDoesntExist() + public void AddImageToAlbum() { - Logger.Debug("CantRemoveFolderThatDoesntExist"); - using (var autoSub = new AutoSubstitute()) + var directoryPath = Faker.System.DirectoryPathWindows(); + var directory = new Directory { - var imageManagementService = autoSub.Resolve(); - - var folder = Faker.System.DirectoryPathWindows(); - SonOfPicassoException exception = null; + Id = Faker.Random.Int(1), + Path = directoryPath, + Images = new List() + }; - var autoResetEvent = new AutoResetEvent(false); - - imageManagementService.RemoveFolder(folder) - .Subscribe(_ => { }, - ex => - { - exception = ex as SonOfPicassoException; - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - exception.Should().NotBeNull(); - exception.Message.Should().Be("Folder does not exist"); - } - } - - [Fact(Timeout = 1000)] - public void CanRemoveFolder() - { - Logger.Debug("CanRemoveFolder"); - using (var autoSub = new AutoSubstitute()) + var images = Faker.Make(Faker.Random.Int(3, 5), () => new Image { - var dataCache = autoSub.Resolve(); - var testPaths = Faker.Make(5, Faker.System.DirectoryPathWindows) - .Distinct() - .ToArray(); + Path = Path.Join(directoryPath) + Faker.System.FileName("jpg"), + DirectoryId = directory.Id + }); - var imageFolderPath = testPaths.First(); - var remainingPaths = testPaths.Skip(1).ToArray(); + directory.Images.AddRange(images); - dataCache.GetFolderList() - .Returns(Observable.Return(testPaths)); + var unitOfWork = Substitute.For(); + unitOfWork.DirectoryRepository.Get() + .ReturnsForAnyArgs(new[] {directory, FakerProfiles.FakeNewDirectory}); - dataCache.SetFolderList(Arg.Any()) - .Returns(Observable.Return(Unit.Default)); + _unitOfWorkQueue.Enqueue(unitOfWork); - dataCache.DeleteFolder(Arg.Any()) - .Returns(Observable.Return(Unit.Default)); + var autoResetEvent = new AutoResetEvent(false); - var imageManagementService = autoSub.Resolve(); + var imageManagementService = _autoSubstitute.Resolve(); - var autoResetEvent = new AutoResetEvent(false); + var albumName = Faker.Random.Words(2); + var albumId = Faker.Random.Int(1); - imageManagementService.RemoveFolder(imageFolderPath) - .Subscribe(_ => autoResetEvent.Set()); + unitOfWork.AlbumRepository.Get().ReturnsForAnyArgs(new[] {new Album {Id = albumId, Name = albumName}}); - autoResetEvent.WaitOne(); + unitOfWork.ImageRepository.GetById(Arg.Any()) + .ReturnsForAnyArgs(info => + { + return images.First(i => i.Id == (int) info.Arg()); + }); - dataCache.Received().SetFolderList(Arg.Is(strings => - strings.SequenceEqual(remainingPaths))); + imageManagementService.AddImagesToAlbum(albumId, images.Select(image => image.Id)) + .Subscribe(unit => autoResetEvent.Set()); - dataCache.Received().DeleteFolder(imageFolderPath); - } - } + _testSchedulerProvider.TaskPool.AdvanceBy(1); - [Fact(Timeout = 1000)] - public void CanAddFolder() - { - Logger.Debug("CanAddFolder"); - using (var autoSub = new AutoSubstitute()) - { - var dataCache = autoSub.Resolve(); - var imageLocationService = autoSub.Resolve(); + autoResetEvent.WaitOne(10).Should().BeTrue(); - var testPaths = Faker.Make(5, Faker.System.DirectoryPathWindows) - .Distinct() - .ToArray(); + unitOfWork.AlbumImageRepository.ReceivedWithAnyArgs(images.Count) + .Insert(null); - var imageFolderPath = testPaths.First(); + unitOfWork.Received(1).Save(); - var imagePaths = Faker.Make(5, () => Faker.System.FileName("png")) - .Select(s => Path.Combine(imageFolderPath, s)) - .ToArray(); - - dataCache.GetFolderList() - .Returns(Observable.Return(testPaths.Skip(1).ToArray())); - - dataCache.SetFolderList(Arg.Any()) - .Returns(Observable.Return(Unit.Default)); - - dataCache.SetFolder(Arg.Any()) - .Returns(Observable.Return(Unit.Default)); - - dataCache.SetImage(Arg.Any()) - .Returns(Observable.Return(Unit.Default)); - - imageLocationService.GetImages(Arg.Any()) - .Returns(Observable.Return(imagePaths)); - - var imageManagementService = autoSub.Resolve(); - - var autoResetEvent = new AutoResetEvent(false); - - ImageFolderModel imageFolderModel = null; - ImageModel[] imageModels = null; - - imageManagementService.AddFolder(imageFolderPath) - .Subscribe(tuple => - { - (imageFolderModel, imageModels) = tuple; - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - imageLocationService.Received().GetImages(imageFolderPath); - - dataCache.Received().SetFolderList(Arg.Is(strings => - strings.OrderBy(s => s) - .SequenceEqual(testPaths.OrderBy(s => s)))); - - dataCache.Received().SetFolder(Arg.Is(folder => - folder.Path == imageFolderPath && - folder.Images.OrderBy(s => s) - .SequenceEqual(imagePaths.OrderBy(s => s)))); - - dataCache.Received(5).SetImage(Arg.Any()); - - dataCache.ReceivedCalls() - .Where(call => call.GetMethodInfo().Name == "SetImage") - .Select(call => (ImageModel)call.GetArguments()[0]) - .Select(model => model.Path) - .Should() - .BeEquivalentTo(imagePaths); - - imageFolderModel.Should().NotBeNull(); - imageFolderModel.Path.Should().Be(imageFolderPath); - - imageModels.Select(model => model.Path) - .Should().BeEquivalentTo(imagePaths); - } + unitOfWork.Received(1).Dispose(); } - [Fact(Timeout = 1000)] - public void CantAddFolderASecondTime() - { - Logger.Debug("CantAddFolderASecondTime"); - using (var autoSub = new AutoSubstitute()) - { - var dataCache = autoSub.Resolve(); - var imageLocationService = autoSub.Resolve(); - - - var testPaths = Faker.Make(5, Faker.System.DirectoryPathWindows) - .Distinct() - .ToArray(); - - var imageFolderPath = testPaths.First(); - - var imagePaths = Faker.Make(5, () => Faker.System.FileName("png")) - .Select(s => Path.Combine(imageFolderPath, s)) - .ToArray(); - - dataCache.GetFolderList() - .Returns(Observable.Return(testPaths)); - - dataCache.SetFolderList(Arg.Any()) - .Returns(Observable.Return(Unit.Default)); - - dataCache.SetFolder(Arg.Any()) - .Returns(Observable.Return(Unit.Default)); - - imageLocationService.GetImages(Arg.Any()) - .Returns(Observable.Return(imagePaths)); - - var imageManagementService = autoSub.Resolve(); - - var autoResetEvent = new AutoResetEvent(false); - - SonOfPicassoException exception = null; - - imageManagementService.AddFolder(imageFolderPath) - .Subscribe( - _ => { }, - ex => - { - exception = ex as SonOfPicassoException; - autoResetEvent.Set(); - }); - - autoResetEvent.WaitOne(); - - imageLocationService.DidNotReceiveWithAnyArgs().GetImages(Arg.Any()); - dataCache.DidNotReceiveWithAnyArgs().SetFolderList(Arg.Any()); - dataCache.DidNotReceiveWithAnyArgs().SetFolder(Arg.Any()); - - exception.Should().NotBeNull(); - exception.Message.Should().Be("Folder already exists"); - } - } - - [Fact(Timeout = 1000)] - public void CanGetImageFolders() + [Fact] + public void ScanFolder() { - Logger.Debug("CanGetImageFolders"); - using (var autoSub = new AutoSubstitute()) - { - var dataCache = autoSub.Resolve(); - - var testPaths = Faker.Make(5, Faker.System.DirectoryPathWindows) - .Distinct() - .ToArray(); - - var imageFolders = testPaths - .Select(s => new ImageFolderModel { Path = s }) - .ToArray(); - - var imageFolderDictionary = imageFolders - .ToDictionary(s => s.Path); - - dataCache.GetFolderList() - .Returns(Observable.Return(testPaths.ToArray())); - - dataCache.GetFolder(Arg.Any()) - .Returns(info => Observable.Return(imageFolderDictionary[info.Arg()])); - - var imageManagementService = autoSub.Resolve(); - - var autoResetEvent = new AutoResetEvent(false); + var directoryPath = Faker.System.DirectoryPathWindows(); + var imagePath = Path.Join(directoryPath, Faker.System.FileName("jpg")); - var results = new List(); - - imageManagementService.GetAllImageFolders() - .Subscribe( - imageFolder => results.Add(imageFolder), - () => autoResetEvent.Set()); - - autoResetEvent.WaitOne(); - - results.Should().BeEquivalentTo(imageFolders); - } - } - - [Fact(Timeout = 1000)] - public void CanGetImages() - { - Logger.Debug("CanGetImages"); - using (var autoSub = new AutoSubstitute()) + var directory = new Directory { - var dataCache = autoSub.Resolve(); - - var testPaths = Faker.Make(5, Faker.System.DirectoryPathWindows) - .Distinct() - .ToArray(); - - var imagePathsByPath = testPaths - .ToDictionary( - testPath => testPath, - testPath => Faker - .Make(5, () => Path.Combine(testPath, Faker.System.FileName("png"))) - .ToArray()); - - var images = imagePathsByPath - .SelectMany(pair => pair.Value) - .Select(imagePath => new ImageModel { Path = imagePath }) - .ToArray(); + Id = Faker.Random.Int(1), + Path = directoryPath, + Images = new List() + }; - var imagesByPath = images - .ToDictionary(image => image.Path); + var unitOfWork = Substitute.For(); + unitOfWork.DirectoryRepository.Get() + .ReturnsForAnyArgs(new[] {directory, FakerProfiles.FakeNewDirectory}); - var imageFolders = testPaths - .Select(testPath => new ImageFolderModel - { - Path = testPath, - Images = imagePathsByPath[testPath] - }) - .ToArray(); + _unitOfWorkQueue.Enqueue(unitOfWork); - var imageFoldersByPath = imageFolders - .ToDictionary(s => s.Path); + _mockFileSystem.AddDirectory(directoryPath); + _mockFileSystem.AddFile(imagePath, new MockFileData(new byte[0])); - dataCache.GetFolderList() - .Returns(Observable.Return(testPaths.ToArray())); + var autoResetEvent = new AutoResetEvent(false); - dataCache.GetFolder(Arg.Any()) - .Returns(info => Observable.Return(imageFoldersByPath[info.Arg()])); + _autoSubstitute.Resolve() + .GetImages(Arg.Any()) + .Returns(Observable.Return(new[] {imagePath})); - dataCache.GetImage(Arg.Any()) - .Returns(info => Observable.Return(imagesByPath[info.Arg()])); + var imageManagementService = _autoSubstitute.Resolve(); + imageManagementService.ScanFolder(directoryPath) + .Subscribe(unit => autoResetEvent.Set()); - var imageManagementService = autoSub.Resolve(); + _testSchedulerProvider.TaskPool.AdvanceBy(1); - var autoResetEvent = new AutoResetEvent(false); + autoResetEvent.WaitOne(10).Should().BeTrue(); - var results = new List(); + unitOfWork.ImageRepository.Received(1) + .Insert(Arg.Any()); - imageManagementService.GetAllImages() - .Subscribe( - image => results.Add(image), - () => autoResetEvent.Set()); + unitOfWork.Received(1) + .Save(); - autoResetEvent.WaitOne(); + unitOfWork.Received(1) + .Dispose(); - results.Should().BeEquivalentTo(images); - } + directory.Images.Count.Should().Be(1); } } } \ No newline at end of file diff --git a/src/SonOfPicasso.Core.Tests/SonOfPicasso.Core.Tests.csproj b/src/SonOfPicasso.Core.Tests/SonOfPicasso.Core.Tests.csproj index fc4548f4..e3696fb8 100644 --- a/src/SonOfPicasso.Core.Tests/SonOfPicasso.Core.Tests.csproj +++ b/src/SonOfPicasso.Core.Tests/SonOfPicasso.Core.Tests.csproj @@ -29,6 +29,7 @@ + diff --git a/src/SonOfPicasso.Core/Interfaces/IDataCache.cs b/src/SonOfPicasso.Core/Interfaces/IDataCache.cs index 0b21de77..4dd6869d 100644 --- a/src/SonOfPicasso.Core/Interfaces/IDataCache.cs +++ b/src/SonOfPicasso.Core/Interfaces/IDataCache.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Reactive; using SonOfPicasso.Core.Models; @@ -9,18 +8,6 @@ public interface IDataCache { IObservable GetUserSettings(); IObservable SetUserSettings(UserSettings userSettings); - - IObservable GetFolderList(); - IObservable SetFolderList(string[] paths); - - IObservable GetFolder(string path); - IObservable SetFolder(ImageFolderModel imageFolder); - IObservable DeleteFolder(string path); - - IObservable GetImage(string path); - IObservable SetImage(ImageModel image); - IObservable DeleteImage(string path); - IObservable Clear(); } } \ No newline at end of file diff --git a/src/SonOfPicasso.Core/Interfaces/IImageManagementService.cs b/src/SonOfPicasso.Core/Interfaces/IImageManagementService.cs index 68d60636..f985a07b 100644 --- a/src/SonOfPicasso.Core/Interfaces/IImageManagementService.cs +++ b/src/SonOfPicasso.Core/Interfaces/IImageManagementService.cs @@ -1,14 +1,17 @@ using System; +using System.Collections.Generic; using System.Reactive; using SonOfPicasso.Core.Models; +using SonOfPicasso.Data.Model; namespace SonOfPicasso.Core.Interfaces { public interface IImageManagementService { - IObservable<(ImageFolderModel, ImageModel[])> AddFolder(string path); - IObservable RemoveFolder(string path); - IObservable GetAllImageFolders(); - IObservable GetAllImages(); + IObservable ScanFolder(string path); + IObservable CreateAlbum(string name); + IObservable AddImagesToAlbum(int albumId, IEnumerable imageIds); + IObservable GetAlbums(); + IObservable DeleteAlbum(int id); } } \ No newline at end of file diff --git a/src/SonOfPicasso.Core/Models/ImageFolderModel.cs b/src/SonOfPicasso.Core/Models/ImageFolderModel.cs deleted file mode 100644 index d73e0d52..00000000 --- a/src/SonOfPicasso.Core/Models/ImageFolderModel.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace SonOfPicasso.Core.Models -{ - public class ImageFolderModel - { - public string[] Images { get; set; } = Array.Empty(); - public string Path { get; set; } - } -} \ No newline at end of file diff --git a/src/SonOfPicasso.Core/Models/ImageModel.cs b/src/SonOfPicasso.Core/Models/ImageModel.cs deleted file mode 100644 index b500dc86..00000000 --- a/src/SonOfPicasso.Core/Models/ImageModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace SonOfPicasso.Core.Models -{ - public class ImageModel - { - public string Path { get; set; } - } -} \ No newline at end of file diff --git a/src/SonOfPicasso.Core/Services/DataCache.cs b/src/SonOfPicasso.Core/Services/DataCache.cs index 9d90c13b..5cb0da42 100644 --- a/src/SonOfPicasso.Core/Services/DataCache.cs +++ b/src/SonOfPicasso.Core/Services/DataCache.cs @@ -9,8 +9,12 @@ namespace SonOfPicasso.Core.Services { public class DataCache : IDataCache { + private static UserSettings CreateUserSettings() + { + return new UserSettings(); + } + private const string UserSettingsKey = "UserSettings"; - private const string ImageFoldersKey = "ImageFolders"; private readonly ILogger _logger; protected readonly IBlobCache BlobCache; @@ -39,11 +43,6 @@ public DataCache(ILogger logger, BlobCache = blobCache; } - public IObservable DeleteImage(string path) - { - throw new NotImplementedException(); - } - public IObservable Clear() { return BlobCache.InvalidateAll(); @@ -60,63 +59,5 @@ public IObservable SetUserSettings(UserSettings userSettings) _logger.Debug("SetUserSettings"); return BlobCache.InsertObject(UserSettingsKey, userSettings); } - - private static UserSettings CreateUserSettings() - { - return new UserSettings(); - } - - public IObservable GetFolderList() - { - _logger.Debug("GetFolderList"); - return BlobCache.GetOrCreateObject(ImageFoldersKey, Array.Empty); - } - - public IObservable SetFolderList(string[] paths) - { - _logger.Debug("SetFolderList: {PathCount}", paths.Length); - return BlobCache.InsertObject(ImageFoldersKey, paths); - } - - public IObservable DeleteFolder(string path) - { - _logger.Debug("DeleteFolder: {Path}", path); - return BlobCache.Invalidate(GetImageFolderKey(path)); - } - - public IObservable GetImage(string path) - { - _logger.Debug("GetImage: {Path}", path); - return BlobCache.GetObject(GetImageKey(path)); - } - - public IObservable SetImage(ImageModel image) - { - _logger.Debug("SetImage: {Path}", image.Path); - return BlobCache.InsertObject(GetImageKey(image.Path), image); - } - - public IObservable GetFolder(string path) - { - _logger.Debug("GetFolder: {Path}", path); - return BlobCache.GetOrCreateObject(GetImageFolderKey(path), () => CreateImageFolder(path)); - } - - private static ImageFolderModel CreateImageFolder(string path) - { - return new ImageFolderModel - { - Path = path - }; - } - - public IObservable SetFolder(ImageFolderModel imageFolder) - { - _logger.Debug("SetFolder"); - return BlobCache.InsertObject(GetImageFolderKey(imageFolder.Path), imageFolder); - } - - private static string GetImageFolderKey(string path) => $"ImageFolder {path}"; - private static string GetImageKey(string path) => $"Image {path}"; } } \ No newline at end of file diff --git a/src/SonOfPicasso.Core/Services/ImageLocationService.cs b/src/SonOfPicasso.Core/Services/ImageLocationService.cs index 06ea01ff..ce61b656 100644 --- a/src/SonOfPicasso.Core/Services/ImageLocationService.cs +++ b/src/SonOfPicasso.Core/Services/ImageLocationService.cs @@ -18,7 +18,9 @@ public class ImageLocationService: IImageLocationService private readonly ISchedulerProvider _schedulerProvider; private readonly ILogger _logger; - public ImageLocationService(ILogger logger, IFileSystem fileSystem, ISchedulerProvider schedulerProvider) + public ImageLocationService(ILogger logger, + IFileSystem fileSystem, + ISchedulerProvider schedulerProvider) { _logger = logger; _fileSystem = fileSystem; diff --git a/src/SonOfPicasso.Core/Services/ImageManagementService.cs b/src/SonOfPicasso.Core/Services/ImageManagementService.cs index 512b9a0d..5c6befb7 100644 --- a/src/SonOfPicasso.Core/Services/ImageManagementService.cs +++ b/src/SonOfPicasso.Core/Services/ImageManagementService.cs @@ -1,110 +1,146 @@ using System; +using System.Collections.Generic; +using System.IO.Abstractions; using System.Linq; using System.Reactive; using System.Reactive.Linq; using Serilog; using SonOfPicasso.Core.Interfaces; -using SonOfPicasso.Core.Models; +using SonOfPicasso.Core.Scheduling; +using SonOfPicasso.Data.Model; +using SonOfPicasso.Data.Repository; namespace SonOfPicasso.Core.Services { public class ImageManagementService : IImageManagementService { - private readonly IDataCache _dataCache; + private readonly IFileSystem _fileSystem; private readonly IImageLocationService _imageLocationService; private readonly ILogger _logger; + private readonly ISchedulerProvider _schedulerProvider; + private readonly Func _unitOfWorkFactory; - public ImageManagementService(IDataCache dataCache, + public ImageManagementService(ILogger logger, + IFileSystem fileSystem, IImageLocationService imageLocationService, - ILogger logger) + Func unitOfWorkFactory, + ISchedulerProvider schedulerProvider) { - _dataCache = dataCache ?? throw new ArgumentNullException(nameof(dataCache)); - _imageLocationService = imageLocationService ?? throw new ArgumentNullException(nameof(imageLocationService)); _logger = logger; + _fileSystem = fileSystem; + _imageLocationService = imageLocationService; + _unitOfWorkFactory = unitOfWorkFactory; + _schedulerProvider = schedulerProvider; } - public IObservable<(ImageFolderModel, ImageModel[])> AddFolder(string path) + public IObservable ScanFolder(string path) { - if (path == null) throw new ArgumentNullException(nameof(path)); + return Observable.StartAsync(async task => + { + using var unitOfWork = _unitOfWorkFactory(); + + if (!_fileSystem.Directory.Exists(path)) + throw new SonOfPicassoException($"Path: `{path}` does not exist"); + + var images = await _imageLocationService.GetImages(path) + .SelectMany(locatedImages => locatedImages) + .Where(s => !unitOfWork.ImageRepository.Get(image => image.Path == path).Any()) + .GroupBy(s => _fileSystem.FileInfo.FromFileName(s).DirectoryName) + .SelectMany(groupedObservable => + { + var directory = unitOfWork.DirectoryRepository + .Get(directory => directory.Path == groupedObservable.Key) + .FirstOrDefault(); + + if (directory == null) + { + directory = new Directory { Path = groupedObservable.Key, Images = new List() }; + unitOfWork.DirectoryRepository.Insert(directory); + } + + return groupedObservable.Select(imagePath => + { + var image = new Image + { + Path = imagePath + }; + + unitOfWork.ImageRepository.Insert(image); + directory.Images.Add(image); + + return image; + }); + }).ToArray(); + + unitOfWork.Save(); + + return images; + }, _schedulerProvider.TaskPool); + } - _logger.Debug("AddFolder {Path}", path); + public IObservable CreateAlbum(string name) + { + return Observable.Start(() => + { + using var unitOfWork = _unitOfWorkFactory(); - return _dataCache.GetFolderList() - .Select(folders => - { - if (folders.Contains(path)) - { - throw new SonOfPicassoException("Folder already exists"); - } - - return _imageLocationService - .GetImages(path) - .Select(images => (folders, images)); - }) - .SelectMany(obs => obs) - .SelectMany(elements => - { - var currentFolders = elements.Item1; - var imagePaths = elements.Item2; + var album = new Album { Name = name }; - var imageFolderModel = new ImageFolderModel { Path = path, Images = imagePaths }; + unitOfWork.AlbumRepository.Insert(album); + unitOfWork.Save(); - var imageModels = imagePaths - .Select(imagePath => new ImageModel{Path = imagePath}) - .ToArray(); + return album; + }, _schedulerProvider.TaskPool); + } - var setImages = imageModels.ToObservable() - .SelectMany(model => _dataCache.SetImage(model)) - .ToArray() - .Select(_ => Unit.Default); + public IObservable GetAlbums() + { + return Observable.Start(() => + { + using var unitOfWork = _unitOfWorkFactory(); - var setFolderList = _dataCache.SetFolderList(currentFolders.Append(path).ToArray()); - var setFolder = _dataCache.SetFolder(imageFolderModel); + var albums = unitOfWork.AlbumRepository.Get() + .ToArray(); - return Observable.Zip(setFolder, setFolderList, setImages) - .Select(_ => (imageFolderModel, imageModels)); - }); + return albums; + }, _schedulerProvider.TaskPool); } - public IObservable RemoveFolder(string path) + public IObservable DeleteAlbum(int id) { - if (path == null) throw new ArgumentNullException(nameof(path)); + return Observable.Start(() => + { + using var unitOfWork = _unitOfWorkFactory(); - _logger.Debug("RemoveFolder {Path}", path); + unitOfWork.AlbumRepository.Delete(id); + unitOfWork.Save(); + + return Unit.Default; + }, _schedulerProvider.TaskPool); + } - return _dataCache.GetFolderList() - .Select(folders => + public IObservable AddImagesToAlbum(int albumId, IEnumerable imageIds) + { + return Observable.Start(() => { - if (!folders.Contains(path)) + using var unitOfWork = _unitOfWorkFactory(); + + var album = unitOfWork.AlbumRepository.GetById(albumId); + + var images = imageIds.Select(imageid => { - throw new SonOfPicassoException("Folder does not exist"); - } + var image = unitOfWork.ImageRepository.GetById(imageid); - var currentFolders = folders.Where(s => s != path).ToArray(); + unitOfWork.AlbumImageRepository.Insert(new AlbumImage { Album = album, Image = image }); - var setFolderList = _dataCache.SetFolderList(currentFolders); - var setFolder = _dataCache.DeleteFolder(path); + return image; + }).ToArray(); - return setFolderList - .SelectMany(setFolder) - .ToArray() - .Select(_ => Unit.Default); - }) - .SelectMany(observable => observable); - } + unitOfWork.Save(); - public IObservable GetAllImageFolders() - { - return _dataCache.GetFolderList() - .SelectMany(strings => strings) - .SelectMany(s => _dataCache.GetFolder(s)); - } - - public IObservable GetAllImages() - { - return this.GetAllImageFolders() - .SelectMany(imageFolder => imageFolder.Images) - .SelectMany(imagePath => _dataCache.GetImage(imagePath)); + return images; + }, _schedulerProvider.TaskPool) + .SelectMany(observable => observable); } } } \ No newline at end of file diff --git a/src/SonOfPicasso.Core/SonOfPicasso.Core.csproj b/src/SonOfPicasso.Core/SonOfPicasso.Core.csproj index a7201d57..16d7426a 100644 --- a/src/SonOfPicasso.Core/SonOfPicasso.Core.csproj +++ b/src/SonOfPicasso.Core/SonOfPicasso.Core.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netcoreapp3.0 false @@ -22,5 +22,9 @@ + + + + diff --git a/src/SonOfPicasso.Data.Tests/SonOfPicasso.Data.Tests.csproj b/src/SonOfPicasso.Data.Tests/SonOfPicasso.Data.Tests.csproj index b1531b4d..d746ab1f 100644 --- a/src/SonOfPicasso.Data.Tests/SonOfPicasso.Data.Tests.csproj +++ b/src/SonOfPicasso.Data.Tests/SonOfPicasso.Data.Tests.csproj @@ -13,7 +13,7 @@ - + @@ -29,6 +29,7 @@ + diff --git a/src/SonOfPicasso.Data.Tests/UnitOfWorkTests.cs b/src/SonOfPicasso.Data.Tests/UnitOfWorkTests.cs index f4032e22..3b0e0761 100644 --- a/src/SonOfPicasso.Data.Tests/UnitOfWorkTests.cs +++ b/src/SonOfPicasso.Data.Tests/UnitOfWorkTests.cs @@ -1,24 +1,12 @@ -using System; -using System.Collections.Generic; -using AutoBogus; -using Autofac.Extras.NSubstitute; -using Bogus; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using SonOfPicasso.Data.Model; +using FluentAssertions; using SonOfPicasso.Testing.Common; using Xunit; using Xunit.Abstractions; namespace SonOfPicasso.Data.Tests { - public class UnitOfWorkTests : TestsBase + public class UnitOfWorkTests : DataTestsBase { - private readonly Faker _newDirectoryFaker = new AutoFaker() - .RuleFor(directory1 => directory1.DirectoryId, 0) - .RuleFor(directory1 => directory1.Images, (List)null) - .RuleFor(directory1 => directory1.Path, faker => faker.System.FilePath()); - public UnitOfWorkTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { @@ -27,31 +15,18 @@ public UnitOfWorkTests(ITestOutputHelper testOutputHelper) [Fact] public void CanSaveAndGetById() { - using (var autoSub = new AutoSubstitute()) + var directory = FakerProfiles.FakeNewDirectory.Generate(); + + using (var unitOfWork = CreateUnitOfWork()) { - var dbContextOptions = - new DbContextOptionsBuilder() - .UseInMemoryDatabase("UnitOfWorkTests"); - - using (var dataContext = new DataContext(dbContextOptions.Options)) - { - autoSub.Provide(dataContext); - var unitOfWorkFactory = autoSub.Resolve>(); - - var directory = (Directory)_newDirectoryFaker; - - using (var unitOfWork = unitOfWorkFactory()) - { - unitOfWork.DirectoryRepository.Insert(directory); - unitOfWork.Save(); - } + unitOfWork.DirectoryRepository.Insert(directory); + unitOfWork.Save(); + } - using (var unitOfWork = unitOfWorkFactory()) - { - var dircopy = unitOfWork.DirectoryRepository.GetById(directory.DirectoryId); - dircopy.Path.Should().Be(dircopy.Path); - } - } + using (var unitOfWork = CreateUnitOfWork()) + { + var dircopy = unitOfWork.DirectoryRepository.GetById(directory.Id); + directory.Should().BeEquivalentTo(dircopy); } } } diff --git a/src/SonOfPicasso.Data/DataContext.cs b/src/SonOfPicasso.Data/Context/DataContext.cs similarity index 95% rename from src/SonOfPicasso.Data/DataContext.cs rename to src/SonOfPicasso.Data/Context/DataContext.cs index 6b26b0c1..c5a7188e 100644 --- a/src/SonOfPicasso.Data/DataContext.cs +++ b/src/SonOfPicasso.Data/Context/DataContext.cs @@ -1,7 +1,7 @@ using Microsoft.EntityFrameworkCore; using SonOfPicasso.Data.Model; -namespace SonOfPicasso.Data +namespace SonOfPicasso.Data.Context { public class DataContext : DbContext, IDataContext { diff --git a/src/SonOfPicasso.Data/IDataContext.cs b/src/SonOfPicasso.Data/Context/IDataContext.cs similarity index 83% rename from src/SonOfPicasso.Data/IDataContext.cs rename to src/SonOfPicasso.Data/Context/IDataContext.cs index f332034f..011ef679 100644 --- a/src/SonOfPicasso.Data/IDataContext.cs +++ b/src/SonOfPicasso.Data/Context/IDataContext.cs @@ -1,8 +1,9 @@ using System; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; -namespace SonOfPicasso.Data +namespace SonOfPicasso.Data.Context { public interface IDataContext: IDisposable { diff --git a/src/SonOfPicasso.Data/Model/Album.cs b/src/SonOfPicasso.Data/Model/Album.cs index a2714590..7af5cdde 100644 --- a/src/SonOfPicasso.Data/Model/Album.cs +++ b/src/SonOfPicasso.Data/Model/Album.cs @@ -1,9 +1,13 @@ namespace SonOfPicasso.Data.Model { - public class Album + public class Album: IAlbum { - public int AlbumId { get; set; } + public int Id { get; set; } public string Name { get; set; } } + + public interface IAlbum: IModel + { + } } \ No newline at end of file diff --git a/src/SonOfPicasso.Data/Model/AlbumImage.cs b/src/SonOfPicasso.Data/Model/AlbumImage.cs index fb3eb6a2..3cdf40b3 100644 --- a/src/SonOfPicasso.Data/Model/AlbumImage.cs +++ b/src/SonOfPicasso.Data/Model/AlbumImage.cs @@ -1,11 +1,15 @@ namespace SonOfPicasso.Data.Model { - public class AlbumImage + public class AlbumImage: IAlbumImage { - public int AlbumImageId { get; set; } + public int Id { get; set; } public int AlbumId { get; set; } public Album Album { get; set; } public int ImageId { get; set; } public Image Image { get; set; } } + + public interface IAlbumImage: IModel + { + } } \ No newline at end of file diff --git a/src/SonOfPicasso.Data/Model/Directory.cs b/src/SonOfPicasso.Data/Model/Directory.cs index 0d5e8ea9..c283931a 100644 --- a/src/SonOfPicasso.Data/Model/Directory.cs +++ b/src/SonOfPicasso.Data/Model/Directory.cs @@ -2,12 +2,16 @@ namespace SonOfPicasso.Data.Model { - public class Directory + public class Directory: IDirectory { - public int DirectoryId { get; set; } + public int Id { get; set; } public string Path { get; set; } public List Images { get; set; } } + + public interface IDirectory: IModel + { + } } \ No newline at end of file diff --git a/src/SonOfPicasso.Data/Model/IModel.cs b/src/SonOfPicasso.Data/Model/IModel.cs new file mode 100644 index 00000000..d67650be --- /dev/null +++ b/src/SonOfPicasso.Data/Model/IModel.cs @@ -0,0 +1,7 @@ +namespace SonOfPicasso.Data.Model +{ + public interface IModel + { + int Id { get; set; } + } +} \ No newline at end of file diff --git a/src/SonOfPicasso.Data/Model/Image.cs b/src/SonOfPicasso.Data/Model/Image.cs index 250d5b79..8a338823 100644 --- a/src/SonOfPicasso.Data/Model/Image.cs +++ b/src/SonOfPicasso.Data/Model/Image.cs @@ -2,9 +2,9 @@ namespace SonOfPicasso.Data.Model { - public class Image + public class Image: IImage { - public int ImageId { get; set; } + public int Id { get; set; } public int DirectoryId { get; set; } @@ -12,4 +12,8 @@ public class Image public Directory Directory { get; set; } } + + public interface IImage: IModel + { + } } \ No newline at end of file diff --git a/src/SonOfPicasso.Data/GenericRepository.cs b/src/SonOfPicasso.Data/Repository/GenericRepository.cs similarity index 92% rename from src/SonOfPicasso.Data/GenericRepository.cs rename to src/SonOfPicasso.Data/Repository/GenericRepository.cs index 11be05dc..a8aa73ef 100644 --- a/src/SonOfPicasso.Data/GenericRepository.cs +++ b/src/SonOfPicasso.Data/Repository/GenericRepository.cs @@ -3,10 +3,11 @@ using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; +using SonOfPicasso.Data.Context; -namespace SonOfPicasso.Data +namespace SonOfPicasso.Data.Repository { - public class GenericRepository where TEntity : class + public class GenericRepository: IGenericRepository where TEntity : class { private readonly IDataContext _context; private readonly DbSet _dbSet; diff --git a/src/SonOfPicasso.Data/Repository/IGenericRepository.cs b/src/SonOfPicasso.Data/Repository/IGenericRepository.cs new file mode 100644 index 00000000..f842d7a5 --- /dev/null +++ b/src/SonOfPicasso.Data/Repository/IGenericRepository.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace SonOfPicasso.Data.Repository +{ + public interface IGenericRepository + { + IEnumerable Get( + Expression> filter = null, + Func, IOrderedQueryable> orderBy = null, + string includeProperties = ""); + + TEntity GetById(object id); + + void Insert(TEntity entity); + + void Delete(object id); + + void Delete(TEntity entityToDelete); + + void Update(TEntity entityToUpdate); + } +} \ No newline at end of file diff --git a/src/SonOfPicasso.Data/Repository/IUnitOfWork.cs b/src/SonOfPicasso.Data/Repository/IUnitOfWork.cs new file mode 100644 index 00000000..1eb1386b --- /dev/null +++ b/src/SonOfPicasso.Data/Repository/IUnitOfWork.cs @@ -0,0 +1,14 @@ +using System; +using SonOfPicasso.Data.Model; + +namespace SonOfPicasso.Data.Repository +{ + public interface IUnitOfWork : IDisposable + { + IGenericRepository AlbumRepository { get; } + IGenericRepository ImageRepository { get; } + IGenericRepository DirectoryRepository { get; } + IGenericRepository AlbumImageRepository { get; } + void Save(); + } +} \ No newline at end of file diff --git a/src/SonOfPicasso.Data/Repository/UnitOfWork.cs b/src/SonOfPicasso.Data/Repository/UnitOfWork.cs new file mode 100644 index 00000000..b1cdd6dc --- /dev/null +++ b/src/SonOfPicasso.Data/Repository/UnitOfWork.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.EntityFrameworkCore; +using SonOfPicasso.Data.Context; +using SonOfPicasso.Data.Model; + +namespace SonOfPicasso.Data.Repository +{ + public class UnitOfWork : IUnitOfWork + { + private readonly IDataContext _dataContext; + + private readonly Lazy> _albumRepository; + public IGenericRepository AlbumRepository => _albumRepository.Value; + + private readonly Lazy> _imageRepository; + public IGenericRepository ImageRepository => _imageRepository.Value; + + private readonly Lazy> _directoryRepository; + public IGenericRepository DirectoryRepository => _directoryRepository.Value; + + private readonly Lazy> _albumImageRepository; + public IGenericRepository AlbumImageRepository => _albumImageRepository.Value; + + public void Save() + { + _dataContext.SaveChanges(); + } + + public UnitOfWork(DbContextOptions dataContextOptions) + { + _dataContext = new DataContext(dataContextOptions); + _albumRepository = new Lazy>(() => new GenericRepository(_dataContext)); + _imageRepository = new Lazy>(() => new GenericRepository(_dataContext)); + _directoryRepository = new Lazy>(() => new GenericRepository(_dataContext)); + _albumImageRepository = new Lazy>(() => new GenericRepository(_dataContext)); + } + + internal bool Disposed; + protected virtual void Dispose(bool disposing) + { + if (!Disposed) + { + if (disposing) + { + _dataContext.Dispose(); + } + } + Disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/SonOfPicasso.Data/UnitOfWork.cs b/src/SonOfPicasso.Data/UnitOfWork.cs deleted file mode 100644 index ece3a4ee..00000000 --- a/src/SonOfPicasso.Data/UnitOfWork.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using SonOfPicasso.Data.Model; - -namespace SonOfPicasso.Data -{ - public class UnitOfWork : IDisposable - { - private readonly IDataContext _context; - - private readonly Lazy> _albumRepository; - public GenericRepository AlbumRepository => _albumRepository.Value; - - private readonly Lazy> _imageRepository; - public GenericRepository ImageRepository => _imageRepository.Value; - - private readonly Lazy> _directoryRepository; - public GenericRepository DirectoryRepository => _directoryRepository.Value; - - private readonly Lazy> _albumImageRepository; - public GenericRepository AlbumImageRepository => _albumImageRepository.Value; - - public void Save() - { - _context.SaveChanges(); - } - - public UnitOfWork(IDataContext dataContext) - { - _context = dataContext; - _albumRepository = new Lazy>(() => new GenericRepository(_context)); - _imageRepository = new Lazy>(() => new GenericRepository(_context)); - _directoryRepository = new Lazy>(() => new GenericRepository(_context)); - _albumImageRepository = new Lazy>(() => new GenericRepository(_context)); - } - - private bool _disposed; - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - } - } - _disposed = true; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/src/SonOfPicasso.Testing.Common/DataGenerator.cs b/src/SonOfPicasso.Testing.Common/DataGenerator.cs deleted file mode 100644 index f60ae542..00000000 --- a/src/SonOfPicasso.Testing.Common/DataGenerator.cs +++ /dev/null @@ -1,19 +0,0 @@ -using AutoBogus; -using Bogus; -using SonOfPicasso.Core.Models; -using SonOfPicasso.Testing.Common.Extensions; - -namespace SonOfPicasso.Testing.Common -{ - public static class DataGenerator - { - static DataGenerator() - { - ImageFolderFaker = new AutoFaker() - .RuleFor(folder => folder.Path, - faker => faker.System.DirectoryPathWindows()); - } - - public static Faker ImageFolderFaker { get; } - } -} \ No newline at end of file diff --git a/src/SonOfPicasso.Testing.Common/DataTestsBase.cs b/src/SonOfPicasso.Testing.Common/DataTestsBase.cs new file mode 100644 index 00000000..96fdca28 --- /dev/null +++ b/src/SonOfPicasso.Testing.Common/DataTestsBase.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; +using Microsoft.EntityFrameworkCore; +using SonOfPicasso.Data.Context; +using SonOfPicasso.Data.Repository; +using Xunit.Abstractions; + +namespace SonOfPicasso.Testing.Common +{ + public class DataTestsBase : TestsBase, IDisposable + { + private readonly string _databasePath; + private readonly DbContextOptions _dbContextOptions; + + public DataTestsBase(ITestOutputHelper testOutputHelper) + : base(testOutputHelper) + { + var databaseRoot = Path.Join(Path.GetTempPath(), "SonOfPicasso.Data.Tests"); + var directoryInfo = new DirectoryInfo(databaseRoot); + if (!directoryInfo.Exists) + { + directoryInfo.Create(); + } + + _databasePath = Path.Join(databaseRoot, $"{Guid.NewGuid()}.db"); + + _dbContextOptions = + new DbContextOptionsBuilder() + .UseSqlite($"Data Source={_databasePath}") + .Options; + + using var dataContext = new DataContext(_dbContextOptions); + dataContext.Database.EnsureCreated(); + } + + protected UnitOfWork CreateUnitOfWork() + { + return new UnitOfWork(_dbContextOptions); + } + + public void Dispose() + { + if (File.Exists(_databasePath)) + { + File.Delete(_databasePath); + } + } + } +} \ No newline at end of file diff --git a/src/SonOfPicasso.Testing.Common/Extensions/FakerSystemExtensions.cs b/src/SonOfPicasso.Testing.Common/Extensions/FakerSystemExtensions.cs index e8b2a644..303012cb 100644 --- a/src/SonOfPicasso.Testing.Common/Extensions/FakerSystemExtensions.cs +++ b/src/SonOfPicasso.Testing.Common/Extensions/FakerSystemExtensions.cs @@ -2,7 +2,7 @@ namespace SonOfPicasso.Testing.Common.Extensions { public static class FakerSystemExtensions { - public static string DirectoryPathWindows(this Bogus.DataSets.System system) - => $@"c:\{system.Random.Word()}\{system.Random.Word()}"; + public static string DirectoryPathWindows(this Bogus.DataSets.System system, int depth = 2, string drive = "c") + => $@"{drive}:\{string.Join(@"\", system.Random.WordsArray(depth))}"; } } \ No newline at end of file diff --git a/src/SonOfPicasso.Testing.Common/FakerProfiles.cs b/src/SonOfPicasso.Testing.Common/FakerProfiles.cs new file mode 100644 index 00000000..0bdd4606 --- /dev/null +++ b/src/SonOfPicasso.Testing.Common/FakerProfiles.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using AutoBogus; +using Bogus; +using SonOfPicasso.Data.Model; +using SonOfPicasso.Testing.Common.Extensions; + +namespace SonOfPicasso.Testing.Common +{ + public static class FakerProfiles + { + public static readonly Faker FakeNewDirectory + = new AutoFaker().RuleFor(directory1 => directory1.Id, 0) + .RuleFor(directory1 => directory1.Images, (List)null) + .RuleFor(directory1 => directory1.Path, faker => faker.System.DirectoryPathWindows()); + + public static readonly Faker FakeDirectory + = new AutoFaker() + .RuleFor(directory1 => directory1.Images, (List)null) + .RuleFor(directory1 => directory1.Path, faker => faker.System.DirectoryPathWindows()); + } +} \ No newline at end of file diff --git a/src/SonOfPicasso.Testing.Common/SonOfPicasso.Testing.Common.csproj b/src/SonOfPicasso.Testing.Common/SonOfPicasso.Testing.Common.csproj index 352c31ed..d404ed02 100644 --- a/src/SonOfPicasso.Testing.Common/SonOfPicasso.Testing.Common.csproj +++ b/src/SonOfPicasso.Testing.Common/SonOfPicasso.Testing.Common.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netcoreapp3.0 false diff --git a/src/SonOfPicasso.UI.Tests/ViewModels/ApplicationViewModelTests.cs b/src/SonOfPicasso.UI.Tests/ViewModels/ApplicationViewModelTests.cs index 3452da49..e0415155 100644 --- a/src/SonOfPicasso.UI.Tests/ViewModels/ApplicationViewModelTests.cs +++ b/src/SonOfPicasso.UI.Tests/ViewModels/ApplicationViewModelTests.cs @@ -1,22 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reactive; -using System.Reactive.Linq; -using System.Threading; -using Autofac.Extras.NSubstitute; -using FluentAssertions; -using NSubstitute; -using SonOfPicasso.Core.Interfaces; -using SonOfPicasso.Core.Models; -using SonOfPicasso.Core.Scheduling; -using SonOfPicasso.Testing.Common; -using SonOfPicasso.Testing.Common.Scheduling; -using SonOfPicasso.UI.Interfaces; -using SonOfPicasso.UI.ViewModels; -using Splat; -using Xunit; +using SonOfPicasso.Testing.Common; using Xunit.Abstractions; namespace SonOfPicasso.UI.Tests.ViewModels @@ -28,89 +10,5 @@ public ApplicationViewModelTests(ITestOutputHelper testOutputHelper) { } - [Fact(Timeout = 500, Skip = "Broken")] - public void CanInitialize() - { - Logger.Debug("CanInitialize"); - using (var autoSub = new AutoSubstitute()) - { - var testSchedulerProvider = new TestSchedulerProvider(); - autoSub.Provide(testSchedulerProvider); - - var imageManagementService = autoSub.Resolve(); - imageManagementService.GetAllImages() - .Returns(Observable.Empty()); - - imageManagementService.GetAllImageFolders() - .Returns(Observable.Empty()); - - var applicationViewModel = autoSub.Resolve(); - - var autoResetEvent = new AutoResetEvent(false); - - applicationViewModel.Initialize() - .Subscribe(_ => autoResetEvent.Set()); - - imageManagementService.Received().GetAllImages(); - imageManagementService.Received().GetAllImageFolders(); - - testSchedulerProvider.MainThreadScheduler.AdvanceBy(1); - - autoResetEvent.WaitOne(); - } - } - - [Fact(Timeout = 500, Skip = "Broken")] - public void CanAddPath() - { - Logger.Debug("CanAddPath"); - using (var autoSub = new AutoSubstitute()) - { - var testSchedulerProvider = new TestSchedulerProvider(); - autoSub.Provide(testSchedulerProvider); - - var imageManagementService = autoSub.Resolve(); - - var directoryPath = Faker.System.DirectoryPath(); - - var imageFiles = Faker.Make(5, () => Path.Combine(directoryPath, Faker.System.FileName("png"))) - .ToArray(); - - var imageFolderModel = new ImageFolderModel { Path = directoryPath, Images = imageFiles }; - - var imageModels = imageFiles - .Select(path => new ImageModel { Path = path }) - .ToArray(); - - imageManagementService.AddFolder(directoryPath) - .Returns(_ => Observable.Return((imageFolderModel, imageModels))); - - var imageViewModels = new List(); - var imageFolderViewModels = new List(); - - var applicationViewModel = autoSub.Resolve(); - - var autoResetEvent = new AutoResetEvent(false); - - applicationViewModel.AddFolder.Execute(directoryPath) - .Subscribe(_ => autoResetEvent.Set()); - - testSchedulerProvider.MainThreadScheduler.AdvanceBy(1); - testSchedulerProvider.MainThreadScheduler.AdvanceBy(1); - - imageManagementService.Received().AddFolder(directoryPath); - - imageViewModels.Should().HaveCount(5); - for (int i = 0; i < imageViewModels.Count; i++) - { - imageViewModels[i].Received().Initialize(imageModels[i]); - } - - imageFolderViewModels.Should().HaveCount(1); - imageFolderViewModels.First().Received().Initialize(imageFolderModel); - - autoResetEvent.WaitOne(); - } - } } } diff --git a/src/SonOfPicasso.UI/App.xaml.cs b/src/SonOfPicasso.UI/App.xaml.cs index 5ffd4e14..3882d0e6 100644 --- a/src/SonOfPicasso.UI/App.xaml.cs +++ b/src/SonOfPicasso.UI/App.xaml.cs @@ -14,6 +14,7 @@ using SonOfPicasso.Core.Scheduling; using SonOfPicasso.Core.Services; using SonOfPicasso.Data; +using SonOfPicasso.Data.Context; using SonOfPicasso.UI.Injection; using SonOfPicasso.UI.Interfaces; using SonOfPicasso.UI.Scheduling; diff --git a/src/SonOfPicasso.UI/Interfaces/IImageFolderViewModel.cs b/src/SonOfPicasso.UI/Interfaces/IImageFolderViewModel.cs index 2d8a8f1c..a952f597 100644 --- a/src/SonOfPicasso.UI/Interfaces/IImageFolderViewModel.cs +++ b/src/SonOfPicasso.UI/Interfaces/IImageFolderViewModel.cs @@ -4,7 +4,7 @@ namespace SonOfPicasso.UI.Interfaces { public interface IImageFolderViewModel { - void Initialize(ImageFolderModel imageFolderModel); + void Initialize(); string Path { get; } } } \ No newline at end of file diff --git a/src/SonOfPicasso.UI/Interfaces/IImageViewModel.cs b/src/SonOfPicasso.UI/Interfaces/IImageViewModel.cs index 2e857535..404e9769 100644 --- a/src/SonOfPicasso.UI/Interfaces/IImageViewModel.cs +++ b/src/SonOfPicasso.UI/Interfaces/IImageViewModel.cs @@ -6,7 +6,7 @@ namespace SonOfPicasso.UI.Interfaces { public interface IImageViewModel { - void Initialize(ImageModel imageModel); + void Initialize(); IObservable GetImage(); string Path { get; } } diff --git a/src/SonOfPicasso.UI/ViewModels/ApplicationViewModel.cs b/src/SonOfPicasso.UI/ViewModels/ApplicationViewModel.cs index 2a189407..8c43882a 100644 --- a/src/SonOfPicasso.UI/ViewModels/ApplicationViewModel.cs +++ b/src/SonOfPicasso.UI/ViewModels/ApplicationViewModel.cs @@ -47,67 +47,12 @@ public ApplicationViewModel(ILogger logger, public IObservable Initialize() { _logger.Debug("Initializing"); - - var getImagesObservable = _imageManagementService.GetAllImages() - .Select(model => - { - var imageViewModel = _imageViewModelFactory(); - imageViewModel.Initialize(model); - return imageViewModel; - }) - .ToArray() - .ObserveOn(_schedulerProvider.MainThreadScheduler) - .Select(models => - { - Images.AddRange(models); - return Unit.Default; - }); - - var getImageFoldersObservable = _imageManagementService.GetAllImageFolders() - .Select(model => - { - var imageFolderViewModel = _imageFolderViewModelFactory(); - imageFolderViewModel.Initialize(model); - return imageFolderViewModel; - }) - .ToArray() - .ObserveOn(_schedulerProvider.MainThreadScheduler) - .Select(models => - { - ImageFolders.AddRange(models); - return Unit.Default; - }); - - return Observable.Zip(getImagesObservable, getImageFoldersObservable) - .Select(_ => Unit.Default); + return Observable.Return(Unit.Default); } private IObservable ExecuteAddFolder(string addPath) { - return _imageManagementService.AddFolder(addPath) - .Select(tuple => - { - var (imageFolderModel, imageModels) = tuple; - var imageFolderViewModel = _imageFolderViewModelFactory(); - imageFolderViewModel.Initialize(imageFolderModel); - - var imageViewModels = imageModels.Select(model => - { - var imageViewModel = _imageViewModelFactory(); - imageViewModel.Initialize(model); - return imageViewModel; - }).ToArray(); - - return (imageFolderViewModel, imageViewModels); - }) - .ObserveOn(_schedulerProvider.MainThreadScheduler) - .Select(tuple => - { - var (imageFolderModel, imageModels) = tuple; - ImageFolders.Add(imageFolderModel); - Images.AddRange(imageModels); - return Unit.Default; - }); + return Observable.Return(Unit.Default); } } } diff --git a/src/SonOfPicasso.UI/ViewModels/ImageFolderViewModel.cs b/src/SonOfPicasso.UI/ViewModels/ImageFolderViewModel.cs index e9d4d0ca..b6d02b1d 100644 --- a/src/SonOfPicasso.UI/ViewModels/ImageFolderViewModel.cs +++ b/src/SonOfPicasso.UI/ViewModels/ImageFolderViewModel.cs @@ -10,13 +10,10 @@ namespace SonOfPicasso.UI.ViewModels [ViewModelView(typeof(ImageFolderViewControl))] public class ImageFolderViewModel : ReactiveObject, IImageFolderViewModel { - private ImageFolderModel _imageFolderModel; + public string Path => ""; - public string Path => _imageFolderModel.Path; - - public void Initialize(ImageFolderModel imageFolderModel) + public void Initialize() { - _imageFolderModel = imageFolderModel ?? throw new ArgumentNullException(nameof(imageFolderModel)); } } } \ No newline at end of file diff --git a/src/SonOfPicasso.UI/ViewModels/ImageViewModel.cs b/src/SonOfPicasso.UI/ViewModels/ImageViewModel.cs index 5fe8567c..ffd36ad7 100644 --- a/src/SonOfPicasso.UI/ViewModels/ImageViewModel.cs +++ b/src/SonOfPicasso.UI/ViewModels/ImageViewModel.cs @@ -18,7 +18,7 @@ public class ImageViewModel : ReactiveObject, IImageViewModel private readonly IImageLoadingService _imageLoadingService; private readonly ISchedulerProvider _schedulerProvider; - public string Path => _imageModel.Path; + public string Path => ""; public ImageViewModel(IImageLoadingService imageLoadingService, ISchedulerProvider schedulerProvider) { @@ -26,13 +26,10 @@ public ImageViewModel(IImageLoadingService imageLoadingService, ISchedulerProvid _schedulerProvider = schedulerProvider; } - public void Initialize(ImageModel imageModel) + public void Initialize() { - _imageModel = imageModel ?? throw new ArgumentNullException(nameof(imageModel)); } - private ImageModel _imageModel; - public IObservable GetImage() { return _imageLoadingService.LoadImageFromPath(Path)