From bede64eaddc64d29d2367de04603d0522093e31e Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Tue, 29 Aug 2023 22:33:05 -0500 Subject: [PATCH] refactor: Rework ConfigCreation unit tests --- .../Config/TemplateConfigCreator.cs | 46 ++++--- .../Config/TemplateConfigCreatorTest.cs | 108 +++------------ .../ConfigCreationProcessorIntegrationTest.cs | 123 ++++++++++++++++++ .../Processors/ConfigCreationProcessorTest.cs | 58 +-------- 4 files changed, 169 insertions(+), 166 deletions(-) create mode 100644 src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorIntegrationTest.cs diff --git a/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs b/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs index 52cc970e..adfdd6d4 100644 --- a/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs +++ b/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; using Recyclarr.Cli.Console.Settings; using Recyclarr.Common.Extensions; @@ -30,7 +29,6 @@ public class TemplateConfigCreator : IConfigCreator return settings.Templates.Any(); } - [SuppressMessage("Design", "CA1031:Do not catch general exception types")] public async Task Create(ICreateConfigSettings settings) { _log.Debug("Creating config from templates: {Templates}", settings.Templates); @@ -41,27 +39,9 @@ public class TemplateConfigCreator : IConfigCreator foreach (var templateFile in matchingTemplateData) { - var destinationFile = _paths.ConfigsDirectory.File(templateFile.Name); - try { - if (destinationFile.Exists && !settings.Force) - { - throw new FileExistsException($"{destinationFile} already exists"); - } - - destinationFile.CreateParentDirectory(); - templateFile.CopyTo(destinationFile.FullName, true); - - // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression - if (destinationFile.Exists) - { - _log.Information("Replacing existing file: {Path}", destinationFile); - } - else - { - _log.Information("Created configuration file: {Path}", destinationFile); - } + CopyTemplate(templateFile, settings); } catch (FileExistsException e) { @@ -75,7 +55,31 @@ public class TemplateConfigCreator : IConfigCreator catch (Exception e) { _log.Error(e, "Unable to save configuration template file"); + throw; } } } + + private void CopyTemplate(IFileInfo templateFile, ICreateConfigSettings settings) + { + var destinationFile = _paths.ConfigsDirectory.File(templateFile.Name); + + if (destinationFile.Exists && !settings.Force) + { + throw new FileExistsException($"{destinationFile} already exists"); + } + + destinationFile.CreateParentDirectory(); + templateFile.CopyTo(destinationFile.FullName, true); + + // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression + if (destinationFile.Exists) + { + _log.Information("Replacing existing file: {Path}", destinationFile); + } + else + { + _log.Information("Created configuration file: {Path}", destinationFile); + } + } } diff --git a/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs b/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs index e141622e..15299946 100644 --- a/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs +++ b/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs @@ -3,10 +3,8 @@ using System.IO.Abstractions.Extensions; using Recyclarr.Cli.Console.Settings; using Recyclarr.Cli.Processors.Config; using Recyclarr.Cli.TestLibrary; -using Recyclarr.TrashLib.Config; using Recyclarr.TrashLib.Config.Services; -using Recyclarr.TrashLib.ExceptionTypes; -using Recyclarr.TrashLib.Repo; +using Recyclarr.TrashLib.Startup; namespace Recyclarr.Cli.Tests.Processors.Config; @@ -35,110 +33,44 @@ public class TemplateConfigCreatorTest : CliIntegrationFixture } [Test, AutoMockData] - public void Throw_when_file_exists_and_not_forced( + public async Task No_replace_when_file_exists_and_not_forced( [Frozen] IConfigTemplateGuideService templates, - MockFileSystem fs, + [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, + [Frozen] IAppPaths paths, ICreateConfigSettings settings, TemplateConfigCreator sut) { - templates.LoadTemplateData().Returns(new[] - { - new TemplatePath - { - Id = "template1", - TemplateFile = fs.CurrentDirectory().File("template-file1.yml"), - Service = SupportedServices.Radarr - } - }); + var templateFile = fs.CurrentDirectory().File("template-file1.yml"); + var destFile = paths.ConfigsDirectory.File(templateFile.Name); + + fs.AddFile(templateFile, new MockFileData("a")); + fs.AddFile(destFile, new MockFileData("b")); settings.Force.Returns(false); - settings.Templates.Returns(new[] - { - "template1" - }); + settings.Path.Returns(templateFile.FullName); - var act = () => sut.Create(settings); + await sut.Create(settings); - act.Should().ThrowAsync(); + fs.GetFile(destFile).TextContents.Should().Be("b"); } [Test, AutoMockData] - public void No_throw_when_file_exists_and_forced( + public async Task No_throw_when_file_exists_and_forced( [Frozen] IConfigTemplateGuideService templates, - MockFileSystem fs, + [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, + [Frozen] IAppPaths paths, ICreateConfigSettings settings, TemplateConfigCreator sut) { - templates.LoadTemplateData().Returns(new[] - { - new TemplatePath - { - Id = "template1", - TemplateFile = fs.CurrentDirectory().File("template-file1.yml"), - Service = SupportedServices.Radarr - } - }); + var templateFile = fs.CurrentDirectory().File("template-file1.yml"); + fs.AddEmptyFile(templateFile); + fs.AddEmptyFile(paths.ConfigsDirectory.File(templateFile.Name)); settings.Force.Returns(true); - settings.Templates.Returns(new[] - { - "template1" - }); + settings.Path.Returns(templateFile.FullName); var act = () => sut.Create(settings); - act.Should().NotThrowAsync(); - } - - [Test] - public async Task Template_id_matching_works() - { - const string templatesJson = - """ - { - "radarr": [ - { - "template": "template-file1.yml", - "id": "template1" - } - ], - "sonarr": [ - { - "template": "template-file2.yml", - "id": "template2" - }, - { - "template": "template-file3.yml", - "id": "template3" - } - ] - } - """; - - var repo = Resolve(); - Fs.AddFile(repo.Path.File("templates.json"), new MockFileData(templatesJson)); - Fs.AddEmptyFile(repo.Path.File("template-file1.yml")); - Fs.AddEmptyFile(repo.Path.File("template-file2.yml")); - // This one shouldn't show up in the result because the user didn't ask for it - Fs.AddEmptyFile(repo.Path.File("template-file3.yml")); - - var settings = Substitute.For(); - settings.Templates.Returns(new[] - { - "template1", - "template2", - // This one shouldn't show up in the results because: - // User specified it, but no template file exists for it. - "template4" - }); - - var sut = Resolve(); - await sut.Create(settings); - - Fs.AllFiles.Should().Contain(new[] - { - Paths.ConfigsDirectory.File("template-file1.yml").FullName, - Paths.ConfigsDirectory.File("template-file2.yml").FullName - }); + await act.Should().NotThrowAsync(); } } diff --git a/src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorIntegrationTest.cs b/src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorIntegrationTest.cs new file mode 100644 index 00000000..04d3e9d5 --- /dev/null +++ b/src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorIntegrationTest.cs @@ -0,0 +1,123 @@ +using System.IO.Abstractions; +using System.IO.Abstractions.Extensions; +using Recyclarr.Cli.Console.Commands; +using Recyclarr.Cli.Console.Settings; +using Recyclarr.Cli.Processors.Config; +using Recyclarr.Cli.TestLibrary; +using Recyclarr.TrashLib.ExceptionTypes; +using Recyclarr.TrashLib.Repo; + +namespace Recyclarr.Cli.Tests.Processors; + +[TestFixture] +[Parallelizable(ParallelScope.All)] +public class ConfigCreationProcessorIntegrationTest : CliIntegrationFixture +{ + [Test] + public async Task Config_file_created_when_using_default_path() + { + var repo = Resolve(); + Fs.AddFile(repo.Path.File("templates.json"), new MockFileData("{}")); + + var sut = Resolve(); + + await sut.Process(new ConfigCreateCommand.CliSettings + { + Path = null + }); + + var file = Fs.GetFile(Paths.AppDataDirectory.File("recyclarr.yml")); + file.Should().NotBeNull(); + file.Contents.Should().NotBeEmpty(); + } + + [Test] + public async Task Config_file_created_when_using_user_specified_path() + { + var sut = Resolve(); + + var settings = new ConfigCreateCommand.CliSettings + { + Path = Fs.CurrentDirectory() + .SubDirectory("user") + .SubDirectory("specified") + .File("file.yml") + .FullName + }; + + await sut.Process(settings); + + var file = Fs.GetFile(settings.Path); + file.Should().NotBeNull(); + file.Contents.Should().NotBeEmpty(); + } + + [Test] + public async Task Should_throw_if_file_already_exists() + { + var sut = Resolve(); + + var settings = new ConfigCreateCommand.CliSettings + { + Path = Fs.CurrentDirectory().File("file.yml").FullName + }; + + Fs.AddEmptyFile(settings.Path); + + var act = () => sut.Process(settings); + + await act.Should().ThrowAsync(); + } + + [Test] + public async Task Template_id_matching_works() + { + const string templatesJson = + """ + { + "radarr": [ + { + "template": "template-file1.yml", + "id": "template1" + } + ], + "sonarr": [ + { + "template": "template-file2.yml", + "id": "template2" + }, + { + "template": "template-file3.yml", + "id": "template3" + } + ] + } + """; + + var repo = Resolve(); + Fs.AddFile(repo.Path.File("templates.json"), new MockFileData(templatesJson)); + Fs.AddEmptyFile(repo.Path.File("template-file1.yml")); + Fs.AddEmptyFile(repo.Path.File("template-file2.yml")); + // This one shouldn't show up in the result because the user didn't ask for it + Fs.AddEmptyFile(repo.Path.File("template-file3.yml")); + + var settings = Substitute.For(); + settings.Templates.Returns(new[] + { + "template1", + "template2", + // This one shouldn't show up in the results because: + // User specified it, but no template file exists for it. + "template4" + }); + + var sut = Resolve(); + await sut.Process(settings); + + Fs.AllFiles.Should().Contain(new[] + { + Paths.ConfigsDirectory.File("template-file1.yml").FullName, + Paths.ConfigsDirectory.File("template-file2.yml").FullName + }); + } +} diff --git a/src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorTest.cs b/src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorTest.cs index 09c91992..5d3f557f 100644 --- a/src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorTest.cs +++ b/src/tests/Recyclarr.Cli.Tests/Processors/ConfigCreationProcessorTest.cs @@ -1,72 +1,16 @@ using System.Diagnostics.CodeAnalysis; -using System.IO.Abstractions; -using System.IO.Abstractions.Extensions; using Autofac.Extras.Ordering; using AutoFixture; using Recyclarr.Cli.Console.Commands; using Recyclarr.Cli.Processors.Config; -using Recyclarr.Cli.TestLibrary; using Recyclarr.TrashLib.ExceptionTypes; namespace Recyclarr.Cli.Tests.Processors; [TestFixture] [Parallelizable(ParallelScope.All)] -public class ConfigCreationProcessorTest : CliIntegrationFixture +public class ConfigCreationProcessorTest { - [Test] - public async Task Config_file_created_when_using_default_path() - { - var sut = Resolve(); - - await sut.Process(new ConfigCreateCommand.CliSettings - { - Path = null - }); - - var file = Fs.GetFile(Paths.AppDataDirectory.File("recyclarr.yml")); - file.Should().NotBeNull(); - file.Contents.Should().NotBeEmpty(); - } - - [Test] - public async Task Config_file_created_when_using_user_specified_path() - { - var sut = Resolve(); - - var settings = new ConfigCreateCommand.CliSettings - { - Path = Fs.CurrentDirectory() - .SubDirectory("user") - .SubDirectory("specified") - .File("file.yml") - .FullName - }; - - await sut.Process(settings); - - var file = Fs.GetFile(settings.Path); - file.Should().NotBeNull(); - file.Contents.Should().NotBeEmpty(); - } - - [Test] - public async Task Should_throw_if_file_already_exists() - { - var sut = Resolve(); - - var settings = new ConfigCreateCommand.CliSettings - { - Path = Fs.CurrentDirectory().File("file.yml").FullName - }; - - Fs.AddEmptyFile(settings.Path); - - var act = () => sut.Process(settings); - - await act.Should().ThrowAsync(); - } - [SuppressMessage("Performance", "CA1812", Justification = "Used implicitly by test methods in this class")] private sealed class EmptyOrderedEnumerable : ICustomization